<pre class='metadata'>
Title: WebGPU Shading Language
Shortname: WGSL
Level: None
Status: w3c/ED
Group: webgpu
ED: https://gpuweb.github.io/gpuweb/wgsl/
TR: https://www.w3.org/TR/WGSL/
Repository: gpuweb/gpuweb
Text Macro: INT i32 or u32
Text Macro: UNSIGNEDINTEGRAL u32 or vecN&lt;u32&gt;
Text Macro: SIGNEDINTEGRAL i32 or vecN&lt;i32&gt;
Text Macro: ALLSIGNEDINTEGRAL AbstractInt, i32, vecN&lt;AbstractInt&gt;, or vecN&lt;i32&gt;
Text Macro: INTEGRAL i32, u32, vecN&lt;i32&gt;, or vecN&lt;u32&gt;
Text Macro: FLOATING f32, f16, vecN&lt;f32&gt;, or vecN&lt;f16&gt;
Text Macro: NUMERIC i32, u32, f32, f16, vecN&lt;i32&gt;, vecN&lt;u32&gt;, vecN&lt;f32&gt;, or vecN&lt;f16&gt;
Text Macro: FLOATSCALAR [=AbstractFloat=], [=f16=], or [=f32=]
Text Macro: ALLINTEGRALDECL S is AbstractInt, i32, or u32<br>T is S or vecN&lt;S&gt;
Text Macro: ALLFLOATINGDECL S is AbstractFloat, f32, or f16<br>T is S or vecN&lt;S&gt;
Text Macro: ALLNUMERICDECL S is AbstractInt, AbstractFloat, i32, u32, f32, or f16<br>T is S, or vecN&lt;S&gt;
Text Macro: ALLSIGNEDNUMERICDECL S is AbstractInt, AbstractFloat, i32, f32, or f16<br>T is S, or vecN&lt;S&gt;
Ignored Vars: i, c0, e, e1, e2, e3, edge, eN, p, s1, s2, sn, AS, AM, N, newbits, M, C, R, v, Stride, Offset, Align, Extent, T, T1

!Participate: <a href="https://github.com/gpuweb/gpuweb/issues/new?labels=wgsl">File an issue</a> (<a href="https://github.com/gpuweb/gpuweb/issues?q=is%3Aissue+is%3Aopen+label%3Awgsl">open issues</a>)
!Tests: <a href=https://github.com/gpuweb/cts/tree/main/src/webgpu/shader/>WebGPU CTS shader/</a>

Editor: Alan Baker, Google https://www.google.com, alanbaker@google.com, w3cid 129277
Editor: Mehmet Oguz Derin, mehmetoguzderin@mehmetoguzderin.com, w3cid 101130
Editor: David Neto, Google https://www.google.com, dneto@google.com, w3cid 99785
Former Editor: Myles C. Maxfield, Apple Inc., mmaxfield@apple.com, w3cid 77180
Former Editor: dan sinclair, Google https://www.google.com, dsinclair@google.com, w3cid 107549
Abstract: Shading language for WebGPU.
Markup Shorthands: markdown yes
Markup Shorthands: biblio yes
Markup Shorthands: idl yes
Markup Shorthands: css no
Assume Explicit For: yes
</pre>

<style>
tr:nth-child(2n) {
  background-color: #b0b0b050;
}
thead {
  background-color: #b0b0b050;
  font-weight: bold;
}
.nowrap {
  white-space:nowrap;
}
.small {
  font-size: smaller;
}
div.syntax {
  display: block;
  page-break-before: avoid;
  padding: .5em 1em;
  background: var(--def-bg);
  border-left: 0.5em solid var(--def-border);
  color: var(--def-text);
  margin-block-start: 1em;
  margin-block-end: 1em;
}
div.syntax > p {
  color: var(--text);
  font-weight: 100;
  margin: 0;
}
div.syntax > p > .choice {
  display: inline-block;
  width: 1em;
  text-align: center;
}
div.syntax > p > a {
  margin-inline-start: 0.1em;
  margin-inline-end: 0.1em;
  font-style: italic;
  font-weight: normal;
  color: var(--text);
}
div.syntax > p > code {
  margin-inline-start: 0.1em;
  margin-inline-end: 0.1em;
  color: var(--text);
  font-style: normal;
  font-weight: bold;
}
div.syntax > p > a > code {
  margin-inline-start: 0.1em;
  margin-inline-end: 0.1em;
  color: var(--text);
  font-style: normal;
  font-weight: bold;
}
[data-dfn-for="syntax"] {
  font-style: italic;
  font-weight: normal;
  color: var(--text);
}
[data-dfn-for="syntax_kw"] {
  margin-inline-start: 0.1em;
  margin-inline-end: 0.1em;
  color: var(--text);
  font-style: normal;
  font-weight: bold;
}
[data-dfn-for="syntax_sym"] {
  margin-inline-start: 0.1em;
  margin-inline-end: 0.1em;
  color: var(--text);
  font-style: normal;
  font-weight: bold;
}
.hidden {
  display: none
}
table.data.builtin tbody{
  border-bottom: 0;
}
table.builtin {
  border-bottom: 2px solid grey;
}
table.builtin tr:nth-child(2n) {
    background-color: #00000000;
}
table.builtin td {
    vertical-align: top;
}
/* Our SVGs aren't responsive to light/dark mode, so they're opaque with a
 * white or black background. Rounded corners make them a bit less jarring. */
object[type="image/svg+xml"] {
    border-radius: .5em;
}
</style>

<pre class=biblio>
{
  "WebGPU": {
    "authors": [
      "Kai Ninomiya",
      "Brandon Jones",
      "Myles C. Maxfield"
    ],
    "href": "https://w3.org/TR/webgpu",
    "title": "WebGPU",
    "status": "Working Draft",
    "publisher": "W3C",
    "deliveredBy": [
      "https://github.com/gpuweb/gpuweb"
    ]
  },
  "WGSL": {
    "authors": [
      "Alan Baker",
      "Mehmet Oguz Derin",
      "David Neto"
    ],
    "href": "https://www.w3.org/TR/WGSL/",
    "title": "WebGPU Shading Language",
    "status": "Working Draft",
    "publisher": "W3C",
    "deliveredBy": [
      "https://github.com/gpuweb/gpuweb"
    ]
  },
  "IEEE-754":{
    "href":"http://ieeexplore.ieee.org/servlet/opac?punumber=4610933",
    "title":"IEEE Standard for Floating-Point Arithmetic",
    "publisher":"Institute of Electrical and Electronics Engineers",
    "isbn":"978-0-7381-5752-8",
    "versions":["IEEE-754-2008","IEEE-754-1985"],
    "id":"IEEE-754",
    "date":"29 August 2008"
  },
  "VulkanMemoryModel": {
    "authors": [
      "Jeff Bolz",
      "Alan Baker",
      "Tobias Hector",
      "David Neto",
      "Robert Simpson",
      "Brian Sumner"
    ],
    "href": "https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#memory-model",
    "title": "Vulkan Memory Model",
    "publisher": "Khronos Group"
  },
  "UnicodeVersion14": {
    "href":"http://www.unicode.org/versions/Unicode14.0.0/",
    "author":"The Unicode Consortium",
    "title":"The Unicode Standard, Version 14.0.0",
    "isbn":"978-1-936213-29-0",
    "id":"UnicodeVersion14"
  },
  "DeRemer1969": {
    "href":"http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-065.pdf",
    "author":"F. L. DeRemer",
    "publisher":"Massachusetts Institute of Technology",
    "date":"24 October 1969",
    "title":"Practical Translators for LR(k) Languages"
  },
  "Muller2005": {
    "title":"On the definition of ulp(x)",
    "href":"https://inria.hal.science/inria-00070503",
    "source":"[Research Report] RR-5504, LIP RR-2005-09, INRIA, LIP",
    "author":"Jean-Michel Muller",
    "publisher":"INRIA",
    "date":"February 2005",
    "rawDate": "2005-02"
  },
  "Jeannerod2013": {
    "href":"https://www.ams.org/journals/mcom/2013-82-284/S0025-5718-2013-02679-8/S0025-5718-2013-02679-8.pdf",
    "title":"Further Analysis of Kahan's Algorithm for the Accurate Computation of 2x2 Determinants",
    "authors": [
      "Claude-Pierre Jeannerod",
      "Nicolas Louvet",
      "Jean-Michel Muller"
    ],
    "publisher": "American Mathematical Society",
    "rawDate":"2013-10",
    "pages": "2245-2264"
  },
  "VanWyk2007": {
    "href":"https://dl.acm.org/doi/10.1145/1289971.1289983",
    "title":"Context-Aware Scanning for Parsing Extensible Languages",
    "authors": [
      "Eric R. Van Wyk",
      "August C. Schwerdfeger"
    ],
    "publisher":"Association for Computing Machinery",
    "series":"GCPE'07",
    "date":"2007"
  }
}
</pre>

<pre class='anchors'>
spec: Vulkan ; urlPrefix: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#
    type: dfn
        text: memory model memory operation; url: memory-model-memory-operation
        text: memory model reference; url: memory-model-references
        text: memory model atomic operation; url: memory-model-atomic-operation
        text: memory model scope; url:memory-model-scope
        text: memory model memory semantics; url:memory-model-memory-semantics
        text: memory model non-private; url: memory-model-non-private
spec: UAX14; urlPrefix: https://www.unicode.org/reports/tr14
    type: dfn
        text: UAX14 Section 6.1 Non-tailorable Line Breaking Rules; url: BreakingRules
        text: UAX14 LB4; url: LB4
        text: UAX14 LB5; url: LB5
spec: UAX31; urlPrefix: https://www.unicode.org/reports/tr31/tr31-35.html
    type: dfn
        text: Unicode Standard Annex #31 for Unicode Version 14.0.0
        text: UAX31 Lexical Classes; url: Table_Lexical_Classes_for_Identifiers
        text: UAX31 Grammar; url: D1
spec: Unicode Character Database for Unicode Version 14.0.0; urlPrefix: https://www.unicode.org/Public/14.0.0/ucd/DerivedCoreProperties.txt
    type: dfn
        text: Unicode Character Database for Unicode Version 14.0.0
spec: UnicodeVersion14; urlPrefix: https://www.unicode.org/versions/Unicode14.0.0/UnicodeStandard-14.0.pdf
    type: dfn
        text: code point; url:
spec: WebGPU; urlPrefix: https://gpuweb.github.io/gpuweb/#
    type: dfn
        text: GPU command; url: gpu-command
        text: RasterizationPoint; url: rasterizationpoint
        text: effective buffer binding size; url: abstract-opdef-effective-buffer-binding-size
        text: binding member; url: binding-member
        text: binding resource type; url: binding-resource-type
        text: binding type; url: binding-type
        text: GPU error scope; url: gpu-error-scope
        text: front-facing; url: front-facing
        text: shader-output mask; url: shader-output-mask
        text: framebuffer; url: framebuffer
        text: normalized device coordinates; url: ndc
        text: clip space coordinates; url: clip-space-coordinates
        text: clip position; url: clip-position
        text: viewport; url: dom-renderstate-viewport-slot
        text: rasterizationpoint-destination; url: rasterizationpoint-destination
        text: rasterizationpoint-depth; url: rasterizationpoint-depth
        text: rasterizationpoint-perspectivedivisor; url: rasterizationpoint-perspectivedivisor
        text: fragmentdestination-position; url: fragmentdestination-position
        for: supported limits
            text: maxComputeWorkgroupStorageSize; url: dom-supported-limits-maxcomputeworkgroupstoragesize
    type: attribute
        for: GPU
            text: wgslLanguageFeatures; url: gpuwgsllanguagefeatures
    type: abstract-op
        text: validating GPUProgrammableStage; url: abstract-opdef-validating-gpuprogrammablestage
</pre>

# Introduction # {#intro}

WebGPU Shading Language (WGSL) is the shader language for [[!WebGPU]].
That is, an application using the WebGPU API uses WGSL to express the programs, known as shaders,
that run on the GPU.

<div class='example wgsl global-scope'>
  <xmp highlight=wgsl>
    // A fragment shader which lights textured geometry with point lights.

    // Lights from a storage buffer binding.
    struct PointLight {
      position : vec3f,
      color : vec3f,
    }

    struct LightStorage {
      pointCount : u32,
      point : array<PointLight>,
    }
    @group(0) @binding(0) var<storage> lights : LightStorage;

    // Texture and sampler.
    @group(1) @binding(0) var baseColorSampler : sampler;
    @group(1) @binding(1) var baseColorTexture : texture_2d<f32>;

    // Function arguments are values from the vertex shader.
    @fragment
    fn fragmentMain(@location(0) worldPos : vec3f,
                    @location(1) normal : vec3f,
                    @location(2) uv : vec2f) -> @location(0) vec4f {
      // Sample the base color of the surface from a texture.
      let baseColor = textureSample(baseColorTexture, baseColorSampler, uv);

      let N = normalize(normal);
      var surfaceColor = vec3f(0);

      // Loop over the scene point lights.
      for (var i = 0u; i < lights.pointCount; i++) {
        let worldToLight = lights.point[i].position - worldPos;
        let dist = length(worldToLight);
        let dir = normalize(worldToLight);

        // Determine the contribution of this light to the surface color.
        let radiance = lights.point[i].color * (1 / pow(dist, 2));
        let nDotL = max(dot(N, dir), 0);

        // Accumulate light contribution to the surface color.
        surfaceColor += baseColor.rgb * radiance * nDotL;
      }

      // Return the accumulated surface color.
      return vec4(surfaceColor, baseColor.a);
    }
  </xmp>
</div>

## Overview ## {#overview}

WebGPU issues a unit of work to the GPU in the form of a [=GPU command=].
WGSL is concerned with two kinds of GPU commands:
* a <dfn noexport>draw command</dfn> executes a [=GPURenderPipeline|render pipeline=]
    in the context of [=shader stage input|inputs=], [=shader stage output|outputs=], and attached [=resources=].
* a <dfn noexport>dispatch command</dfn> executes a [=GPUComputePipeline|compute pipeline=]
    in the context of [=shader stage input|inputs=] and attached [=resources=].

Both kinds of pipelines use shaders written in WGSL.

A <dfn noexport>shader</dfn> is the portion of a WGSL program that executes a [=shader stage=] in a pipeline.
A shader comprises:
* An [=entry point=] [=function/function=].
* The transitive closure of all called functions, starting with the entry point.
    This set includes both [=user-defined function|user-defined=] and [=built-in function|built-in=] functions.
    (For a more rigorous definition, see "[=functions in a shader stage=]".)
* The set of variables and constants [=statically accessed=] by all those functions.
* The set of types used to define or analyze all those functions, variables, and constants.

Note: A WGSL program does not require an [=entry point=]; however, such a
program cannot be executed by the API because an entry point is required to
create a {{GPUProgrammableStage}}.

When executing a shader stage, the implementation:
* Computes the values of constants declared at [=module scope|module-scope=].
* Binds [=resources=] to variables in the shader's [=resource interface of a shader|resource interface=],
    making the contents of those resources available to the shader during execution.
* Allocates memory for other [=module scope|module-scope=] variables,
    and populates that memory with the specified initial values.
* Populates the formal parameters of the entry point, if they exist, with the shader stage's inputs.
* Connects the entry point [=return value=], if one exists, to the shader stage's outputs.
* Then it invokes the entry point.

A WGSL program is organized into:
* [[#directives|Directives]], which specify module-level behavior controls.
* [[#functions|Functions]], which specify execution behavior.
* [[#statements|Statements]], which are declarations or units of executable behavior.
* [[#literals|Literals]], which are text representations for pure mathematical values.
* [[#value-decls|Constants]], each providing a name for a value computed at a specific time.
* [[#var-decls|Variables]], each providing a name for memory holding a value.
* [[#expressions|Expressions]], each of which combines a set of values to produce a result value.
* [[#types|Types]], each of which describes:
    * A set of values.
    * Constraints on supported expressions.
    * The semantics of those expressions.
* [[#attributes|Attributes]], which modify an object to specify extra information such as:
    * Specifying the [[#shader-interface|interfaces]] to [[#entry-points|entry points]].
    * Specifying [[#diagnostic-filtering|diagnostic filters]].

Note: A WGSL program is currently composed of a single [[#wgsl-module|WGSL module]].

WGSL is an imperative language: behavior is specified as a sequence of statements to execute.
Statements can:
* Declare [[#value-decls|constants]] or [[#var-decls|variables]].
* Modify the contents of variables.
* Modify execution order using structured programming constructs:
    * Selective execution: [[#if-statement|if]] (with optional `else if` and `else` clauses), [[#switch-statement|switch]].
    * Repetition: [[#loop-statement|loop]], [[#while-statement|while]], [[#for-statement|for]].
    * Escaping a nested execution construct: [[#continue-statement|continue]], [[#break-statement|break]], [[#break-if-statement|break if]].
    * Refactoring: [[#function-calls|function call]] and [[#return-statement|return]].
* Evaluate expressions to compute values as part of the above behaviors.
* Check [[#const-assert-statement|assumptions]] at [=shader module creation|shader creation=] time on [=const-expression|constant expressions=].

WGSL is statically typed: each value computed by a particular expression is in a specific type,
determined only by examining the program source.

WGSL has types describing [[#bool-type|booleans]] and numbers
([[#integer-types|integers]] and [[#floating-point-types|floating point]]).
These types can be aggregated into [[#composite-types|composites]]
([[#vector-types|vectors]], [[#matrix-types|matrices]],
[[#array-types|arrays]], and [[#struct-types|structures]]).
WGSL has special types (e.g. [[#atomic-types|atomics]]) that provide unique operations.
WGSL describes the types that can be stored in [[#memory|memory]] as [[#memory-views|memory views]].
WGSL provides commonly used rendering types in the form of
[[#texture-sampler-types|textures and samplers]].
These types have associated [[#texture-builtin-functions|built-in functions]]
to expose commonly provided GPU hardware for graphics rendering.

WGSL does not have implicit conversions or promotions from [=type/concrete=]
types, but does provide implicit conversions and promotions from
[=type/abstract=] types.
Converting a value from one [=type/concrete=] numeric or boolean type to
another requires an explicit [[#value-constructor-builtin-function|conversion]],
[=value constructor=], or [[#bitcast-builtin|reinterpretation of
bits]]; however, WGSL does provide some limited facility to promote [=scalar=]
types to [=vector=] types.
This also applies to [=composite=] types.

The work of a shader stage is partitioned into one or more <dfn noexport>invocations</dfn>,
each of which executes the entry point, but under slightly different conditions.
Invocations in a shader stage share access to certain variables:
* All invocations in the stage share the resources in the shader interface.
* In a [=compute shader stage|compute shader=], invocations in the same
     [=compute shader stage/workgroup=] share
     variables in the [=address spaces/workgroup=] [=address space=].
     Invocations in different workgroups do not share those variables.

However, the invocations act on different sets of shader stage inputs, including built-in inputs
that provide an identifying value to distinguish an invocation from its peers.
Each invocation has its own independent memory space in the form
of variables in the [=address spaces/private=] and [=address spaces/function=] address spaces.

Invocations within a shader stage execute concurrently, and may often execute in parallel.
The shader author is responsible for ensuring the dynamic behavior of the invocations
in a shader stage:
* Meet the [[#uniformity|uniformity]] requirements of certain primitive operations, including texture sampling and control barriers.
* Coordinate potentially conflicting accesses to shared variables, to avoid data races.

WGSL sometimes permits several possible behaviors for a given feature.
This is a portability hazard, as different implementations may exhibit the different behaviors.
The design of WGSL aims to minimize such cases, but is constrained by feasibility,
and goals for achieving high performance across a broad range of devices.

<dfn noexport>Behavioral requirements</dfn> are actions the implementation will
perform when processing or executing a WGSL program. They describe the
implementation's obligations in the contract with the programmer.
The specification explicitly states these obligations when they might not be otherwise obvious.

## Syntax Notation ## {#syntax-notation}

Following syntax notation describes the conventions of the syntactic grammar of WGSL:

* Italic text on both sides of a rule indicates a syntax rule.
* Bold monospace text starting and ending with single quotes (**'**) on the right-hand side of a rule indicates keywords and tokens.
* A colon (**:**) in regular text registers a syntax rule.
* A vertical bar (**|**) in regular text indicates alternatives.
* An question mark (**?**) in regular text indicates that previous keyword, token, rule, or group occurs zero or one times (is optional).
* An asterisk (<b>*</b>) in regular text indicates that previous keyword, token, rule, or group occurs zero or more times.
* A plus (**+**) in regular text indicates that previous keyword, token, rule, or group occurs one or more times.
* A matching pair of opening parenthesis (**(**) and closing parenthesis (**)**) in regular text indicates a group of elements.

## Mathematical Terms and Notation ## {#terms-and-notation}

<dfn noexport>Angles</dfn>:
* By convention, angles are measured in radians.
* The reference ray for measuring angles is the ray from the origin (0,0) toward (+&infin;,0).
* Let &theta; be the angle subtended by a comparison ray and the reference ray.
    Then &theta; increases as the comparison ray moves counterclockwise.
* There are 2 &pi; radians in a complete circle.
* Examples:
    * The angle 0 points from the origin to the right, toward (1,0)
    * The angle 2&pi; points from the origin to the right, toward (1,0)
    * The angle &pi;/4 points from the origin to the point (1,1)
    * The angle &pi;/2 points from the origin to the point (0,1)
    * The angle &pi; points from the origin to the point (-1,0)
    * The angle (3/2)&pi; points from the origin to the point (0,-1)

A <dfn noexport>hyperbolic angle</dfn> is a unitless area, not an angle in the traditional
sense. Specifically:

*   Consider the hyperbola |x|<sup>2</sup> - |y|<sup>2</sup> = 1 for |x| &gt; 0.

*   Let |R| be a ray from the origin to some point (|x|, |y|) on the hyperbola.

*   Let |a| be twice the area enclosed by |R|, the |x| axis, and the curve of the hyperbola
    itself.

*   Consider |a| to be positive when |R| is above the |x| axis, and negative when below.

Then the area |a| is a hyperbolic angle such that |x| is the hyperbolic cosine of |a|, and
|y| is the hyperbolic sine of |a|.

An <dfn noexport>interval</dfn> is a contiguous set of numbers with a lower and upper bound.
Depending on context, they are sets of integers, floating point numbers, or real numbers.
* The closed interval [*a*,*b*] is the set of numbers *x* such that *a* &le; *x* &le; *b*.
* The half-open interval [*a*,*b*) is the set of numbers *x* such that *a* &le; *x* &lt; *b*.
* The half-open interval (*a*,*b*] is the set of numbers *x* such that *a* &lt; *x* &le; *b*.

The <dfn noexport>floor expression</dfn> is defined over real numbers |x| extended with &plus;&infin; and &minus;&infin;:

* &lfloor; &plus; &infin; &rfloor; = &plus;&infin;
* &lfloor; &minus; &infin; &rfloor; = &minus;&infin;
* for real number |x|, &lfloor;|x|&rfloor; = |k|, where |k| is the unique integer such that |k| &le; |x| &lt; |k|+1

The <dfn noexport>ceiling expression</dfn> is defined over real numbers |x| extended with &plus;&infin; and &minus;&infin;:

* &lceil; &plus;&infin; &rceil; = &plus;&infin;
* &lceil; &minus;&infin; &rceil; = &minus;&infin;
* for real number |x|, &lceil;|x|&rceil; = |k|, where |k| is the unique integer such that |k|-1 &lt; |x| &le; |k|

The <dfn noexport>truncate</dfn> function is defined over real numbers |x| extended with &plus;&infin; and &minus;&infin;:

* truncate(&plus;&infin;) = &plus;&infin;
* truncate(&minus;&infin;) = &minus;&infin;
* for real number |x|, computes the nearest whole number whose absolute value is less than or equal to the absolute value of |x|:
    * truncate(|x|) = &lfloor;|x|&rfloor; if |x| &ge; 0, and &lceil;|x|&rceil; if |x| &lt; 0.

The <dfn noexport>roundUp</dfn> function is defined for positive integers |k| and |n| as:

* roundUp(|k|, |n|) = &lceil;|n| &div; |k|&rceil; &times; |k|

The <dfn noexport>transpose</dfn> of an |c|-column |r|-row matrix |A| is the |r|-column |c|-row matrix
|A|<sup>T</sup> formed by copying the rows of |A| as the columns of |A|<sup>T</sup>:

* transpose(|A|) = |A|<sup>T</sup>
* transpose(|A|)<sub>|i|,|j|</sub> = |A|<sub>|j|,|i|</sub>

The transpose of a column vector is defined by interpreting the column vector as a 1-row matrix.
Similarly, the transpose of a row vector is defined by interpreting the row vector as a 1-column matrix.

# WGSL Module # {#wgsl-module}

A WGSL program is composed of a single WGSL module.

A module is a sequence of optional [=directives=] followed by [=module scope=] [=declarations=] and [[#const-assert-statement|const_assert statements]].
A module is organized into:
* [[#directives|Directives]], which specify module-level behavior controls.
* [[#functions|Functions]], which specify execution behavior.
* [[#statements|Statements]], which are declarations or units of executable behavior.
* [[#literals|Literals]], which are text representations for pure mathematical values.
* [[#var-decls|Variables]], each providing a name for memory holding a value.
* [[#value-decls|Constants]], each providing a name for a value computed at a specific time.
* [[#expressions|Expressions]], each of which combines a set of values to produce a result value.
* [[#types|Types]], each of which describes:
    * A set of values.
    * Constraints on supported expressions.
    * The semantics of those expressions.
* [[#attributes|Attributes]], which modify an object to specify extra information such as:
    * Specifying the [[#shader-interface|interfaces]] to [[#entry-points|entry points]].
    * Specifying [[#diagnostic-filtering|diagnostic filters]].

<pre class=include>
path: syntax/translation_unit.syntax.bs.include
</pre>

<pre class=include>
path: syntax/global_decl.syntax.bs.include
</pre>

## Shader Lifecycle ## {#shader-lifecycle}

There are four key events in the lifecycle of a WGSL program and the shaders it may contain.
The first two correspond to the WebGPU API methods used to prepare a WGSL program
for execution.
The last two are the start and end of execution of a shader.

The events are:

1. <dfn noexport>Shader module creation</dfn>
    * This occurs when the
        WebGPU {{GPUDevice/createShaderModule()}} method
        is called.
        The source text for a WGSL program is provided at this time.
2. <dfn noexport>Pipeline creation</dfn>
    * This occurs when the
        WebGPU {{GPUDevice/createComputePipeline()}} method
        or the
        WebGPU {{GPUDevice/createRenderPipeline()}} method
        is invoked.
        These methods use one or more previously created shader modules, together with other
        configuration information.
    * Only the code forming the [=shader=] of the specified [=entry point=] of the
        {{GPUProgrammableStage}} is considered during pipeline creation.
        That is, code unrelated to the entry point is effectively stripped before compilation.
    * Note: Each [=shader stage=] is considered to be compiled separately and, thus, might
        include different portions of the module.
3. <dfn noexport>Shader execution start</dfn>
    * This occurs when a [=draw command|draw=] or [=dispatch command=] is issued to the GPU,
        begins executing the pipeline,
        and invokes the [=shader stage=] [=entry point=] function.
4. <dfn noexport>Shader execution end</dfn>
    * This occurs when all work in the shader completes:
        * all its [=invocations=] terminate, and
        * all accesses to [=resources=] complete, and
        * outputs, if any, are passed to downstream pipeline stages.

The events are ordered due to:
*  data dependencies: shader execution requires a pipeline, and a pipeline requires a shader module.
*  causality: the shader must start executing before it can finish executing.

## Errors ## {#errors}

A WebGPU implementation may fail to process a shader for two reasons:

* A <dfn export>program error</dfn> occurs if the shader does not satisfy the requirements of the WGSL or WebGPU specifications.
* An <dfn noexport>uncategorized error</dfn> may occur
    even when all WGSL and WebGPU requirements have been satisfied.
    Possible causes include:
    * The shaders are too complex, exceeding the capabilities of the implementation,
        but in a way not easily captured by prescribed [[#limits|limits]].
        Simplifying the shaders may work around the issue.
    * A defect in the WebGPU implementation.


A processing error may occur during three phases in the shader lifecycle:

* A <dfn export>shader-creation error</dfn>
    is an error feasibly detectable at [=shader module creation=] time.
    Detection relies only on the WGSL module source text
    and other information available to the `createShaderModule` API method.
    Statements in this specification that describe something the program *must*
    do generally produce a shader-creation error if those assertions are violated.

* A <dfn export>pipeline-creation error</dfn>
    is an error detectable at [=pipeline creation=] time.
    Detection relies on the WGSL module source text
    and other information available to the particular pipeline creation API method.
    These errors are only triggered for code present in the [=shader=] of the
    [=entry point=] being compiled for the {{GPUProgrammableStage}}.

* A <dfn export>dynamic error</dfn> is an error occurring during shader execution.
    These errors may or may not be detectable.

Note: For example, a data race may not be detectable.

Each requirement [=behavioral requirement|will=] be checked at the earliest opportunity.
That is:
* A shader-creation error results when failing to meet a requirement detectable at shader-creation time.
* A pipeline-creation error results when failing to meet a requirement detectable at pipeline-creation time,
    but not detectable earlier.

When unclear from context, this specification indicates
whether failure to meet a particular requirement
results in a shader-creation, pipeline-creation, or dynamic error.

The consequences of an error are as follows:
* A WGSL module with a [=shader-creation error=] or [=pipeline-creation error=] error will not be incorporated
    into a [=pipeline=] and hence will not be executed.
* Detectable errors [=behavioral requirement|will=] [=triggered|trigger=] a [=diagnostic=].
* If a [=dynamic error=] occurs:
    * [=Memory accesses=] [=behavioral requirement|will=] be restricted to:
        * [=shader stage inputs=],
        * [=shader stage outputs=],
        * any part of a [=resource=] bound to a variable in the WGSL module, and
        * other variables declared in the WGSL module.
    * Otherwise, the program may not behave as described in the rest of this specification.
        Note: These effects may be non-local.

## Diagnostics ## {#diagnostics}

An implementation can generate [=diagnostics=] during [=shader module creation=] or [=pipeline creation=].
A <dfn noexport>diagnostic</dfn> is a message produced by the implementation for the benefit of the application author.

A diagnostic is created, or <dfn noexport>triggered</dfn>, when a particular condition is met,
known as the <dfn dfn-for="diagnostic">triggering rule</dfn>.
The place in the source text where the condition is met, expressed as a point or range in the source text, is known as the
<dfn dfn-for="diagnostic">triggering location</dfn>.

A [=diagnostic=] has the following properties:
* A [=diagnostic/severity=].
* A [=diagnostic/triggering rule=].
* A [=diagnostic/triggering location=].

The <dfn dfn-for="diagnostic">severity</dfn> of a diagnostic is one of the following, ordered from greatest to least:
: <dfn dfn-for="severity" noexport>error</a>
:: The diagnostic is an error.
     This corresponds to a [=shader-creation error=] or to a [=pipeline-creation error=].
: <dfn dfn-for="severity" noexport>warning</a>
:: The diagnostic describes an anomaly that merits the attention of the application developer, but is not an error.
: <dfn dfn-for="severity" noexport>info</a>
:: The diagnostic describes a notable condition that merits attention of the application developer, but is not an error or warning.
: <dfn dfn-for="severity" noexport>off</a>
:: The diagnostic is disabled. It will not be conveyed to the application.

The name of a [=diagnostic/triggering rule=] is either:
* a [=syntax/diagnostic_name_token=], or
* two [=syntax/diagnostic_name_token=] tokens, separated by a period `'.'` (U+002E).

<pre class=include>
path: syntax/diagnostic_rule_name.syntax.bs.include
</pre>

### Diagnostic Processing ### {#diagnostic-processing}

Triggered diagnostics [=behavioral requirement|will=] be processed as follows:
1. For each diagnostic *D*, find the [=diagnostic filter=]
    with the smallest [=affected range=] that contains D's [=diagnostic/triggering location=], and which has the same [=diagnostic/triggering rule=].
    * If such a filter exists, apply it to *D*, updating *D*'s [=diagnostic/severity=].
    * Otherwise *D* remains unchanged.
2. Discard diagnostics that have severity [=severity/off=].
3. If at least one remaining diagnostic *DI* has severity [=severity/info=], then:
    * Other [=severity/info=] diagnostics with same triggering rule *may* be discarded, leaving only the original diagnostic *DI*.
4. If at least one remaining diagnostic *DW* has severity [=severity/warning=], then:
    * Other [=severity/info=] or [=severity/warning=] diagnostics with same triggering rule *may* be discarded, leaving only the original diagnostic *DW*.
5. If at least one remaining diagnostic has [=severity/error=] severity, then:
    * Other diagnostics *may* be discarded, including other diagnostics with [=severity/error=] severity.
    * A [=program error=] is generated.
         * The error is a [=shader-creation error=] if the diagnostic was triggered at [=shader module creation=] time.
         * The error is a [=pipeline-creation error=] if the diagnostic was triggered at [=pipeline creation=] time.
6. If processing during [=shader module creation=] time, the remaining diagnostics populate the
    {{GPUCompilationInfo/messages}} member of the WebGPU {{GPUCompilationInfo}} object.
7. If processing during [=pipeline creation=], [=severity/error=] diagnostics
    result in WebGPU validation failure when validating {{GPUProgrammableStage}}.

Note: The rules allow an implementation to stop processing a WGSL module as soon as an error is detected.
Additionally, an analysis for a particular kind of warning can stop on the first warning,
and an analysis for a particular kind of info diagnostic can stop on the first occurrence.
WGSL does not specify the order to perform different kinds of analyses, or an ordering within a single analysis.
Therefore, for the same WGSL module, different implementations may report different instances of diagnostics with the same severity.

### Filterable Triggering Rules ### {#filterable-triggering-rules}

Most [=diagnostics=] are unconditionally reported to the WebGPU application.
Some kinds of diagnostics can be [[#diagnostic-filtering|filtered]], in part by naming their [=diagnostic/triggering rule=].
The following table lists the standard set of triggering rules that can be filtered.

<table class='data'>
  <caption>Filterable diagnostic triggering rules</caption>
  <thead>
    <tr><th>Filterable Triggering Rule<th>Default Severity<th>Triggering Location<th>Description
  </thead>

  <tr>
    <td><dfn noexport dfn-for="trigger">derivative_uniformity</dfn>
    <td>[=severity/error=]
    <td>The location of the [=call site=] for any
        [=builtin functions that compute a derivative|builtin function that computes a derivative=].
        That is, the location of a call to any of:
        * the [[#derivative-builtin-functions|derivative builtin functions]]
        * [[#texturesample|textureSample]]
        * [[#texturesamplebias|textureSampleBias]]
        * [[#texturesamplecompare|textureSampleCompare]]

    <td>A call to a builtin function computes derivatives, but [=uniformity analysis=] cannot prove that the call occurs in [=uniform control flow=].

    See [[#uniformity]].
</table>

Using an unrecognized triggering rule consisting of a single [=diagnostic name-token=] should trigger a warning from the user agent.

An implementation may support triggering rules not specified here,
provided they are spelled using the multiple-token form of [=syntax/diagnostic_rule_name=].
Using an unrecognized triggering rule spelled in the multiple-token form *may* itself trigger a diagnostic.

Future versions of this specification may remove a particular rule or weaken its default severity
(i.e. replace its current default with a less severe default) and still be deemed as satisfying backward compatibility.
For example, a future version of WGSL may change the default severity for [=trigger/derivative_uniformity=] from `error` to either `warning` or `info`.
After such a change to the specification, previously valid programs would remain valid.

### Diagnostic Filtering ### {#diagnostic-filtering}

Once a [=diagnostic=] with a filterable [=diagnostic/triggering rule=] is [=triggered=], WGSL provides mechanisms to discard the diagnostic, or to modify its severity.

A <dfn noexport>diagnostic filter</dfn> *DF* has three parameters:
* *AR*: a range of source text known as the <dfn noexport>affected range</dfn>
* *NS*: a new [=diagnostic/severity=]
* *TR*: a [=diagnostic/triggering rule=]

Applying a diagnostic filter *DF*(*AR*,*NS*,*TR*) to a diagnostic *D* has the following effect:
* If *D*'s [=diagnostic/triggering location=] is in *AR* and *D*'s [=diagnostic/triggering rule=] is *TR*, then
        set *D*'s [=diagnostic/severity=] property to *NS*.
* Otherwise, *D* is unchanged.

A <dfn noexport>range diagnostic filter</dfn> is a [=diagnostic filter=] whose [=affected range=] is a specified
range of source text.
A range diagnostic filter is specified as a `@diagnostic` [=attribute=] at the start of the affected source range,
as specified in the following table.
A `@diagnostic` attribute [=shader-creation error|must not=] appear anywhere else.

<table class='data'>
  <caption>Placement of a range diagnostic filter</caption>
  <thead>
    <tr><th>Placement<th>Affected Range
  </thead>
    <tr><td>[=syntax/compound_statement|Beginning=] of a [=compound statement=].<td>The compound statement.
    <tr><td>[=syntax/function_decl|Beginning=] of a [=function declaration=].<td>The function declaration.
    <tr><td>[=syntax/if_statement|Beginning=] of an [=statement/if=] statement.<td>The if statement: the [=syntax/if_clause=]
      and all associated [=syntax/else_if_clause=] and [=syntax/else_clause=] clauses,
      including all controlling condition expressions.
    <tr><td>[=syntax/switch_statement|Beginning=] of a [=statement/switch=] statement.<td>The switch statement: the selector expression and the [=syntax/switch_body=].
    <tr><td>[=syntax/switch_body|Beginning=] of a [=syntax/switch_body=].<td>The [=syntax/switch_body=].
    <tr><td>[=syntax/loop_statement|Beginning=] of a [=statement/loop=] statement.<td>The loop statement.
    <tr><td>[=syntax/while_statement|Beginning=] of a [=statement/while=] statement.<td>The while statement: both the condition expression and the loop body.
    <tr><td>[=syntax/for_statement|Beginning=] of a [=statement/for=] statement.<td>The for statement: the [=syntax/for_header=] and the loop body.
    <tr><td>Immediately before the opening brace (`'{'`) of the [=loop body=] of a [=statement/loop=], [=statement/while=], or [=statement/for=] loop.<td>The [=loop body=].
    <tr><td>[=syntax/continuing_compound_statement|Beginning=] of a [=syntax/continuing_compound_statement=].<td>The [=syntax/continuing_compound_statement=].
</table>

Note: The following are also [=compound statements=]:
a [=function body=], a [=case clause=], a [=default-alone clause=],
the bodies of [=statement/while=] and [=statement/for=] loops,
and the bodies of [=syntax/if_clause=], [=syntax/else_if_clause=], and [=syntax/else_clause=].

<div class='example wgsl global-scope' heading='Range diagnostic filter on texture sampling'>
  <xmp highlight=wgsl>
  var<private> d: f32;
  fn helper() -> vec4<f32> {
    // Disable the derivative_uniformity diagnostic in the
    // body of the "if".
    if (d < 0.5) @diagnostic(off,derivative_uniformity) {
      return textureSample(t,s,vec2(0,0));
    }
    return vec4(0.0);
  }
  </xmp>
</div>

A [=global diagnostic filter=] can be used to apply a diagnostic filter to the entire WGSL module.

<div class='example wgsl global-scope' heading='Global diagnostic filter for derivative uniformity'>
  <xmp highlight=wgsl>
  diagnostic(off,derivative_uniformity);
  var<private> d: f32;
  fn helper() -> vec4<f32> {
    if (d < 0.5) {
      // The derivative_uniformity diagnostic is disabled here
      // by the global diagnostic filter.
      return textureSample(t,s,vec2(0,0));
    } else {
      // The derivative_uniformity diagnostic is set to 'warning' severity.
      @diagnostic(warning,derivative_uniformity) {
        return textureSample(t,s,vec2(0,0));
      }
    }
    return vec4(0.0);
  }
  </xmp>
</div>

Two [=diagnostic filters=] *DF*(*AR1*,*NS1*,*TR1*) and *DF*(*AR2*,*NS2*,*TR2*) <dfn dfn-for="diagnostic">conflict</dfn> when:
* (*AR1* &equals; *AR2*), and
* (*TR1* &equals; *TR2*), and
* (*NS1* &ne; *NS2*).

[=Diagnostic filters=] [=shader-creation error|must=] not [=diagnostic/conflict=].

WGSL's diagnostic filters are designed so their affected ranges nest perfectly.
If the affected range of DF1 overlaps with the affected range of DF2, then
either DF1's affected range is fully contained in DF2's affected range, or the other way around.

The <dfn noexport>nearest enclosing diagnostic filter</dfn> for source location *L* and triggering rule *TR*,
if one exists, is the diagnostic filter *DF(AR,NS,TR)* where:
* *L* falls in the affected range *AR*, and
* If there is another filter *DF'(AR',NS',TR)* where *L* falls in *AR'*, then *AR* is contained in *AR'*.

Because affected ranges nest, the nearest enclosing diagnostic is unique, or does not exist.

## Limits ## {#limits}

A WGSL implementation [=behavioral requirement|will=] support shaders that
satisfy the following limits.
A WGSL implementation may support shaders that go beyond the specified limits.

Note: A WGSL implementation should issue an error if it does not support a
shader that goes beyond the specified limits.

<table class='data'>
  <caption>Quantifiable shader complexity limits</caption>
  <thead>
    <tr><th>Limit<th>Minimum supported value
  </thead>
    <tr><td>Maximum number of members in a [=structure=] type<td>1023
    <tr><td>Maximum [=nesting depth=] of a [=composite=] type<td>15
    <tr><td>Maximum nesting depth of brace-enclosed statements in a function<td>127
    <tr><td>Maximum number of [=formal parameter|parameters=] for a function<td>255
    <tr><td>Maximum number of case selector values in a [=statement/switch=] statement.
            The sum of, for each case statement, the number of case values,
            including the [=default clause=].
        <td>1023

    <tr><td>Maximum combined [=byte-size=] of all [=variables=] instantiated in the
            [=address spaces/private=] address space that are [=statically accessed=] by a single
            [=shader=]

            For the purposes of this limit, [=bool=] has a size of 4 bytes.
        <td>8192
    <tr><td>Maximum combined [=byte-size=] of all [=variables=] instantiated in the
            [=address spaces/function=] address space that are declared in a single
            [=function/function=]

            For the purposes of this limit, [=bool=] has a size of 4 bytes.
        <td>8192
    <tr><td>Maximum combined [=byte-size=] of all [=variables=] instantiated in the
            [=address spaces/workgroup=] address space that are [=statically accessed=] by a single
            [=shader=]

            For the purposes of this limit, [=bool=] has a size of 4 bytes and a
            [=fixed footprint|fixed-footprint=] array is treated as a [=creation-fixed
            footprint=] array when substituting the override value.

            This maps the WebGPU [=supported limits/maxComputeWorkgroupStorageSize=] limit
            into a standalone WGSL limit.
        <td>[=supported limits/maxComputeWorkgroupStorageSize|16384=]
    <tr><td>Maximum number of elements in [=const-expression=] of [=array=] type<td>2047
</table>

# Textual Structure # {#textual-structure}

The `text/wgsl` media type is used to identify content as a WGSL module.
See [[#text-wgsl-media-type]].

A WGSL module is Unicode text using the UTF-8 encoding, with no byte order mark (BOM).

WGSL module text consists of a sequence of Unicode [=code points=], grouped into contiguous non-empty sets forming:
* [=comments=]
* [=tokens=]
* [=blankspaces=]

The program text [=shader-creation error|must not=] include a null code point (`U+0000`).

## Parsing ## {#parsing}

To parse a WGSL module:
<blockquote>
1. Remove [=comments=]:
    * Replace the first comment with a space code point (`U+0020`).
    * Repeat until no comments remain.
2. Find [=template lists=], using the [=template list discovery|algorithm=] in [[#template-lists-sec]].
3. Parse the whole text, attempting to match the [=syntax/translation_unit=] grammar rule.
    Parsing uses a LALR(1) parser (one token of lookahead) [[!DeRemer1969]], with the following customization:
    * Tokenization is interleaved with parsing, and is context-aware.
        When the parser requests the next token:
        * Consume and ignore an initial sequence of [=blankspace=] code points.
        * If the next code point is the start of a [=template list=], consume it and return [=syntax_sym/_template_args_start=].
        * If the next code point is the end of a [=template list=], consume it and return [=syntax_sym/_template_args_end=].
        * Otherwise:
            * A <dfn>token candidate</dfn> is any WGSL [=token=] formed from the non-empty prefix of the remaining unconsumed code points.
            * The token returned is the longest [=token candidate=] that is also a valid lookahead token for the current parser state. [[!VanWyk2007]]

</blockquote>

A [=shader-creation error=] results if:
* the entire source text cannot be converted into a finite sequence of valid tokens, or
* the [=syntax/translation_unit=] grammar rule does not match the entire token sequence.

## Blankspace and Line Breaks ## {#blankspace-and-line-breaks}

<dfn>Blankspace</dfn> is any combination of one or more of code points from the Unicode
[=Unicode Standard Annex #31 for Unicode Version 14.0.0|Pattern_White_Space=] property.
The following is the set of code points in [=Unicode Standard Annex #31 for Unicode Version 14.0.0|Pattern_White_Space=]:
* space (`U+0020`)
* horizontal tab (`U+0009`)
* line feed (`U+000A`)
* vertical tab (`U+000B`)
* form feed (`U+000C`)
* carriage return (`U+000D`)
* next line (`U+0085`)
* left-to-right mark (`U+200E`)
* right-to-left mark (`U+200F`)
* line separator (`U+2028`)
* paragraph separator (`U+2029`)

A <dfn>line break</dfn> is a contiguous sequence of [=blankspace=] code points indicating the end of a line.
It is defined as the blankspace signalling a "mandatory break" as defined by
[=UAX14 Section 6.1 Non-tailorable Line Breaking Rules=] [=UAX14 LB4|LB4=] and [=UAX14 LB5|LB5=].
That is, a line break is any of:
* line feed (`U+000A`)
* vertical tab (`U+000B`)
* form feed (`U+000C`)
* carriage return (`U+000D`) when not also followed by line feed (`U+000A`)
* carriage return (`U+000D`) followed by line feed (`U+000A`)
* next line (`U+0085`)
* line separator (`U+2028`)
* paragraph separator (`U+2029`)

Note: Diagnostics that report source text locations in terms of line numbers should use [=line breaks=] to
count lines.

## Comments ## {#comments}

A <dfn>comment</dfn> is a span of text that does not influence the validity or meaning of a WGSL
program, except that a comment can separate [=tokens=].
Shader authors can use comments to document their programs.

A <dfn noexport>line-ending comment</dfn> is a kind of [=comment=] consisting
of the two code points `//` (`U+002F` followed by `U+002F`) and the code points that follow,
up until but not including:
* the next [=line break=], or
* the end of the program.

A <dfn noexport>block comment</dfn> is a kind of [=comment=] consisting of:
* The two code points `/*` (`U+002F` followed by `U+002A`)
* Then any sequence of:
    * A [=block comment=], or
    * Text that does not contain either `*/` (`U+002A` followed by `U+002F`)
        or `/*` (`U+002F` followed by `U+002A`)
* Then the two code points `*/` (`U+002A` followed by `U+002F`)

Note: Block comments can be nested.
Since a block comment requires matching start and end text sequences, and allows arbitrary nesting,
a block comment cannot be recognized with a regular expression.
This is a consequence of the Pumping Lemma for Regular Languages.

<div class='example wgsl' heading='Comments'>
  <xmp highlight=wgsl>
  const f = 1.5; // This is line-ending comment.
  const g = 2.5; /* This is a block comment
                  that spans lines.
                  /* Block comments can nest.
                   */
                  But all block comments must terminate.
                 */
  </xmp>
</div>

## Tokens ## {#tokens}

A <dfn>token</dfn> is a contiguous sequence of code points forming one of:
* a [=literal=].
* a [=keyword=].
* a [=reserved word=].
* a [=syntactic token=].
* an [=identifier=].
* a [=context-dependent name=].

## Literals ## {#literals}

A <dfn>literal</dfn> is one of:
* A <dfn noexport>boolean literal</dfn>: either `true` or `false`.
* A <dfn>numeric literal</dfn>: either an [=integer literal=] or a [=floating point literal=],
    and is used to represent a number.

<pre class=include>
path: syntax/literal.syntax.bs.include
</pre>

### Boolean Literals ### {#boolean-literals}

<div class='example wgsl bool-literals' heading='boolean literals'>
  <xmp highlight=wgsl>
    const a = true;
    const b = false;
  </xmp>
</div>

<pre class=include>
path: syntax/bool_literal.syntax.bs.include
</pre>

### Numeric Literals ### {#numeric-literals}

The form of a [=numeric literal=] is defined via pattern-matching.

An <dfn>integer literal</dfn> is:
* An integer specified as any of:
    * `0`
    * A sequence of decimal digits, where the first digit is not `0`.
    * `0x` or `0X` followed by a sequence of hexadecimal digits.
* Then an optional `i` or `u` suffix.

Note: A leading zero on a non-zero integer literal (e.g. 012) is forbidden,
so as to avoid confusion with other languages' leading-zero-means-octal notation.

<pre class=include>
path: syntax/int_literal.syntax.bs.include
</pre>

<pre class=include>
path: syntax/decimal_int_literal.syntax.bs.include
</pre>

<div class='example wgsl decimal-int-literals' heading='decimal integer literals'>
  <xmp highlight=wgsl>
    const a = 1u;
    const b = 123;
    const c = 0;
    const d = 0i;
  </xmp>
</div>

<pre class=include>
path: syntax/hex_int_literal.syntax.bs.include
</pre>

<div class='example wgsl hexadecimal-int-literals' heading='hexadecimal integer literals'>
  <xmp highlight=wgsl>
    const a = 0x123;
    const b = 0X123u;
    const c = 0x3f;
  </xmp>
</div>

A <dfn>floating point literal</dfn> is either a [=decimal floating point literal=]
or a [=hexadecimal floating point literal=].

<pre class=include>
path: syntax/float_literal.syntax.bs.include
</pre>

A [=floating point literal=] has two logical parts: a mantissa to representing a fraction, and an optional exponent.
Roughly, the value of the literal is the mantissa multiplied by a base value raised to the given exponent.
A mantissa digit is <dfn dfn-for="mantissa">significant</dfn> if it is non-zero,
or if there are mantissa digits to its left and to its right that are both non-zero.
Significant digits are counted from left-to-right: the *N*'th significant digit has *N*-1 significant digits
to its left.

A <dfn noexport>decimal floating point literal</dfn> is:
* A mantissa, specified as a sequence of digits, with an optional decimal point (`.`) somewhere among them.
    The mantissa represents a fraction in base 10 notation.
* Then an optional exponent suffix consisting of:
    * `e` or `E`.
    * Then an exponent specified as an decimal number with an optional leading sign (`+` or `-`).
    * Then an optional `f` or `h` suffix.
* At least one of the decimal point, or the exponent, or the `f` or `h` suffix
     [=shader-creation error|must=] be present.
     If none are, then the token is instead an [=integer literal=].

<pre class=include>
path: syntax/decimal_float_literal.syntax.bs.include
</pre>

<div class='example wgsl decimal-float-literals' heading='decimal floating point literals'>
  <xmp highlight=wgsl>
    const a = 0.e+4f;
    const b = 01.;
    const c = .01;
    const d = 12.34;
    const f = .0f;
    const g = 0h;
    const h = 1e-3;
  </xmp>
</div>

<div algorithm="mathematical value of decimal floating point literal">
The mathematical value of a [=decimal floating point literal=] is computed as follows:
* Compute |effective_mantissa| from |mantissa|:
    * If |mantissa| has 20 or fewer [=mantissa/significant=] digits, then |effective_mantissa| is |mantissa|.
    * Otherwise:
        * Let |truncated_mantissa| be the same as |mantissa| except each digit to the
             right of the 20th significant digit is replaced with 0.
        * Let |truncated_mantissa_next| be the same as |mantissa| except:
             * the 20th significant digit is incremented by 1, and carries are propagated to the left as needed
                 needed to ensure each digit remains in the range 0 through 9, and
             * each digit to the right of the 20th significant digit is replaced with 0.
        * Set |effective_mantissa| to either |truncated_mantissa| or |truncated_mantissa_next|.
             This is an implementation choice.
* The mathematical value of the literal is the mathematical value of |effective_mantissa| as a decimal fraction,
    multiplied by 10 to the power of the exponent.
    When no exponent is specified, an exponent of 0 is assumed.

</div>

Note: The decimal mantissa is truncated after 20 decimal digits, preserving approximately log(10)/log(2)&times;20 &approx; 66.4 significant bits in the fraction.


A <dfn noexport>hexadecimal floating point literal</dfn> is:
* A `0x` or `0X` prefix
* Then a mantissa, specified as a sequence of hexadecimal digits, with an optional hexadecimal point (`.`) somewhere among them.
    The mantissa represents a fraction in base 16 notation.
* Then an optional exponent suffix consisting of:
    * `p` or `P`
    * Then an exponent specified as an decimal number with an optional leading sign (`+` or `-`).
    * Then an optional `f` or `h` suffix.
* At least one of the hexadecimal point, or the exponent [=shader-creation error|must=] be present.
     If neither are, then the token is instead an [=integer literal=].

<pre class=include>
path: syntax/hex_float_literal.syntax.bs.include
</pre>

<div class='example wgsl hexadecimal-float-literals' heading='hexadecimal floating point literals'>
  <xmp highlight=wgsl>
    const a = 0xa.fp+2;
    const b = 0x1P+4f;
    const c = 0X.3;
    const d = 0x3p+2h;
    const e = 0X1.fp-4;
    const f = 0x3.2p+2h;
  </xmp>
</div>

<div algorithm="mathematical value of hexadecimal floating point literal">
The mathematical value of a [=hexadecimal floating point literal=] is computed as follows:
* Compute *effective_mantissa* from *mantissa*:
    * If *mantissa* has 16 or fewer [=mantissa/significant=] digits, then *effective_mantissa* is *mantissa*.
    * Otherwise:
        * Let |truncated_mantissa| be the same as |mantissa| except each digit to the
             right of the 16th significant digit is replaced with 0.
        * Let |truncated_mantissa_next| be the same as |mantissa| except:
             * the 16th significant digit is incremented by 1, and carries are propagated to the left as needed
                 needed to ensure each digit remains in the range 0 through `f`, and
             * each digit to the right of the 16th significant digit is replaced with 0.
        * Set |effective_mantissa| to either |truncated_mantissa| or |truncated_mantissa_next|.
             This is an implementation choice.
* The mathematical value of the literal is the mathematical value of |effective_mantissa| as a hexadecimal fraction,
    multiplied by 2 to the power of the exponent.
    When no exponent is specified, an exponent of 0 is assumed.

</div>

Note: The hexadecimal mantissa is truncated after 16 hexadecimal digits, preserving approximately 4 &times;16 &equals; 64 significant bits in the fraction.


When a [=numeric literal=] has a suffix, the literal denotes a value in a specific [=type/concrete=] [=scalar=] type.
Otherwise, the literal denotes a value one of the [=abstract numeric types=] defined below.
In either case, the value denoted by the literal is its mathematical value after conversion to the target type,
following the rules in [[#floating-point-conversion]].

<table class=data>
  <caption>Mapping numeric literals to types</caption>
  <thead>
    <tr><th>Numeric Literal<th>Suffix<th>Type<th>Examples
  </thead>

  <tr><td>[=integer literal=]<td>`i`<td>[=i32=]<td>42i
  <tr><td>[=integer literal=]<td>`u`<td>[=u32=]<td>42u
  <tr><td>[=integer literal=]<td><td>[=AbstractInt=]<td>124
  <tr><td>[=floating point literal=]<td>`f`<td>[=f32=]<td>42f 1e5f 1.2f 0x1.0p10f
  <tr><td>[=floating point literal=]<td>`h`<td>[=f16=]<td>42h 1e5h 1.2h 0x1.0p10h
  <tr><td>[=floating point literal=]<td><td>[=AbstractFloat=]<td>1e5 1.2 0x1.0p10
</table>

A [=shader-creation error=] results if:
* An [=integer literal=] with a `i` or `u` suffix cannot be represented by the target type.
* A [=hexadecimal floating point literal=] with a `f` or `h` suffix overflows or cannot be exactly represented by the target type.
* A [=decimal floating point literal=] with a `f` or `h` suffix overflows the target type.
* A [=floating point literal=] with a `h` suffix is used while the [=extension/f16|f16 extension=] is not enabled.

Note: The hexadecimal float value 0x1.00000001p0 requires 33 mantissa bits to be represented exactly,
but [=f32=] only has 23 explicit mantissa bits.

Note: If you want to use an `f` suffix to force a hexadecimal float literal to be of type, the literal must also
use a binary exponent.  For example, write `0x1p0f`.  In comparison, `0x1f` is a hexadecimal integer literal.

## Keywords ## {#keywords}

A <dfn>keyword</dfn> is a [=token=] which refers to a predefined language concept.
See [[#keyword-summary]] for the list of WGSL keywords.

## Identifiers ## {#identifiers}

An <dfn>identifier</dfn> is a kind of [=token=] used as a name.
See [[#declaration-and-scope]].

WGSL uses two grammar nonterminals to separate use cases:
* An [=syntax/ident=] is used to name a declared object.
* A [=syntax/member_ident=] is used to name a [=member=] of a [=structure=] type.

<pre class=include>
path: syntax/ident.syntax.bs.include
</pre>
<pre class=include>
path: syntax/member_ident.syntax.bs.include
</pre>

The form of an identifier is based on the
[=Unicode Standard Annex #31 for Unicode Version 14.0.0|Unicode Standard Annex #31=] for
[[!UnicodeVersion14|Unicode Version 14.0.0]],
with the following elaborations.

Identifiers use the following profile described in terms of [=UAX31 Grammar=]:

```
<Identifier> := <Start> <Continue>* (<Medial> <Continue>+)*

<Start> := XID_Start + U+005F
<Continue> := <Start> + XID_Continue
<Medial> :=
```

This means identifiers with non-ASCII code points like these are
valid: `Δέλτα`, `réflexion`, `Кызыл`, `𐰓𐰏𐰇`, `朝焼け`, `سلام`, `검정`, `שָׁלוֹם`, `गुलाबी`, `փիրուզ`.

With the following exceptions:
* An identifier [=shader-creation error|must not=] have the same spelling as a [=keyword=] or as a [=reserved word=].
* An identifier [=shader-creation error|must not=] be `_` (a single underscore, `U+005F`).
* An identifier [=shader-creation error|must not=] start with `__` (two underscores, `U+005F` followed by `U+005F`).

<pre class=include>
path: syntax/ident_pattern_token.syntax.bs.include
</pre>

[=Unicode Character Database for Unicode Version 14.0.0=] includes non-normative listing
with all valid code points
of both [=UAX31 Lexical Classes|XID_Start=] and
[=UAX31 Lexical Classes|XID_Continue=].

Note: The [=return type=] for some [=built-in functions=] are structure types whose name cannot be used WGSL source.
Those structure types are described as if they were [=predeclared=] with a name starting with two underscores.
The result value can be saved into newly declared `let` or `var` using type inferencing, or immediately have one of its members
immediately extracted by name.  See example usages in the description of `frexp` and `modf`.

### Identifier Comparison ### {#identifier-comparison}

Two WGSL identifiers are the same if and only if they consist of the same sequence of code points.

Note: This specification does not permit Unicode normalization of values for the purposes of comparison.
Values that are visually and semantically identical but use different Unicode character sequences will not match.
Content authors are advised to use the same encoding sequence consistently or to avoid potentially troublesome
characters when choosing values. For more information, see [[CHARMOD-NORM]].

Note: A user agent should issue developer-visible warnings when the meaning of a WGSL module would change if
all instances of an identifier are replaced with one of that identifier's homographs.
(A homoglyph is a sequence of code points that may appear the same to a reader as another sequence of code points.
Examples of mappings to detect homoglyphs are the transformations, mappings, and matching algorithms mentioned in
the previous paragraph. Two sequences of code points are homographs if the identifier can transform one into the other by
repeatedly replacing a subsequence with its homoglyph.)

## Context-Dependent Names ## {#context-dependent-names}

A <dfn>context-dependent name</dfn> is a [=token=] used to name a concept, but only in specific grammatical contexts.
The spelling of the token may be the same as an [=identifier=], but the token does not [=resolve=] to a declared object.
This section lists the tokens used as [=context-dependent names=].
The token must not be a [=keyword=] or [=reserved word=].

### Attribute Names ### {#attribute-names}

See [[#attributes]].

The [=syntax/attribute=] names are:

* <a for=attribute lt=align>`'align'`</a>
* <a for=attribute lt=binding>`'binding'`</a>
* <a for=attribute lt=builtin>`'builtin'`</a>
* <a for=attribute lt=compute>`'compute'`</a>
* <a for=attribute lt=const>`'const'`</a>
* <a for=attribute lt=diagnostic>`'diagnostic'`</a>
* <a for=attribute lt=fragment>`'fragment'`</a>
* <a for=attribute lt=group>`'group'`</a>
* <a for=attribute lt=id>`'id'`</a>
* <a for=attribute lt=interpolate>`'interpolate'`</a>
* <a for=attribute lt=invariant>`'invariant'`</a>
* <a for=attribute lt=location>`'location'`</a>
* <a for=attribute lt=blend_src>`'blend_src'`</a>
* <a for=attribute lt=must_use>`'must_use'`</a>
* <a for=attribute lt=size>`'size'`</a>
* <a for=attribute lt=vertex>`'vertex'`</a>
* <a for=attribute lt=workgroup_size>`'workgroup_size'`</a>

### Built-in Value Names ### {#builtin-value-names}

A <dfn noexport>built-in value name-token</dfn> is a [=token=] used in the name of a [=built-in value=].

See [[#builtin-inputs-outputs]].

<pre class=include>
path: syntax/builtin_value_name.syntax.bs.include
</pre>

The [=built-in value=] names are:

* <a for="built-in values" lt=vertex_index>`'vertex_index'`</a>
* <a for="built-in values" lt=instance_index>`'instance_index'`</a>
* <a for="built-in values" lt=position>`'position'`</a>
* <a for="built-in values" lt=front_facing>`'front_facing'`</a>
* <a for="built-in values" lt=frag_depth>`'frag_depth'`</a>
* <a for="built-in values" lt=sample_index>`'sample_index'`</a>
* <a for="built-in values" lt=sample_mask>`'sample_mask'`</a>
* <a for="built-in values" lt=local_invocation_id>`'local_invocation_id'`</a>
* <a for="built-in values" lt=local_invocation_index>`'local_invocation_index'`</a>
* <a for="built-in values" lt=global_invocation_id>`'global_invocation_id'`</a>
* <a for="built-in values" lt=workgroup_id>`'workgroup_id'`</a>
* <a for="built-in values" lt=num_workgroups>`'num_workgroups'`</a>

### Diagnostic Rule Names ### {#diagnostic-rule-names}

A <dfn noexport>diagnostic name-token</dfn> is a [=token=] used in the name of a diagnostic [=diagnostic/triggering rule=].

See [[#diagnostics]].

<pre class=include>
path: syntax/diagnostic_name_token.syntax.bs.include
</pre>

The pre-defined [=diagnostic/triggering rule|diagnostic rule=] names are:

* <a for=trigger lt=derivative_uniformity>`'derivative_uniformity'`</a>

### Diagnostic Severity Control Names ### {#diagnostic-severity-control-names}

The valid [=diagnostic filter=] severity control names are listed in [[#diagnostics]] but have the same form as an [=identifier=]:

<pre class=include>
path: syntax/severity_control_name.syntax.bs.include
</pre>

The [=diagnostic filter=] severity control names are:

* <a for=severity lt=error>`'error'`</a>
* <a for=severity lt=warning>`'warning'`</a>
* <a for=severity lt=info>`'info'`</a>
* <a for=severity lt=off>`'off'`</a>

### Extension Names ### {#extension-names}

The valid [=enable-extension=] names are listed in [[#enable-extensions-sec]] but in general have the same form as an [=identifier=]:

<pre class=include>
path: syntax/enable_extension_name.syntax.bs.include
</pre>

The [=enable-extension=] names are:

* <a for=extension lt=f16>`'f16'`</a>
* <a for=extension lt=clip_distances>`'clip_distances'`</a>
* <a for=extension lt=dual_source_blending>`'dual_source_blending'`</a>

The valid [=language extension=] names are listed in [[#language-extensions-sec]] but in general have the same form as an [=identifier=]:

<pre class=include>
path: syntax/software_extension_name.syntax.bs.include
</pre>

The [=language extension=] names are:

* <a for=language_extension lt=readonly_and_readwrite_storage_textures>`'readonly_and_readwrite_storage_textures'`</a>
* <a for=language_extension lt=packed_4x8_integer_dot_product>`'packed_4x8_integer_dot_product'`</a>
* <a for=language_extension lt=unrestricted_pointer_parameters>`'unrestricted_pointer_parameters'`</a>
* <a for=language_extension lt=pointer_composite_access>`'pointer_composite_access'`</a>

### Interpolation Type Names ### {#interpolation-type-names}

An <dfn noexport>interpolation type name-token</dfn> is a [=token=] used in the name of an [=interpolation type=]
for [=syntax/interpolate_type_name=].

See [[#interpolation]].

The [=interpolation type=] names are:

* <a for="interpolation type" lt=perspective>`'perspective'`</a>
* <a for="interpolation type" lt=linear>`'linear'`</a>
* <a for="interpolation type" lt=flat>`'flat'`</a>

### Interpolation Sampling Names ### {#interpolation-sampling-names}

An <dfn noexport>interpolation sampling name-token</dfn> is a [=token=] used in the name of an [=interpolation sampling=].

See [[#interpolation]].

<pre class=include>
path: syntax/interpolate_sampling_name.syntax.bs.include
</pre>

The [=interpolation sampling=] names are:

* <a for="interpolation sampling" lt=center>`'center'`</a>
* <a for="interpolation sampling" lt=centroid>`'centroid'`</a>
* <a for="interpolation sampling" lt=sample>`'sample'`</a>
* <a for="interpolation sampling" lt=first>`'first'`</a>
* <a for="interpolation sampling" lt=either>`'either'`</a>

### Swizzle Names ### {#swizzle-names}

The [=swizzle=] names are used in [[#vector-access-expr|vector access expressions]]:

<pre class=include>
path: syntax/swizzle_name.syntax.bs.include
</pre>

## Template Lists ## {#template-lists-sec}

<dfn noexport>Template parameterization</dfn> is a way to specify parameters that modify a general concept.
To write a template parameterization, write the general concept, followed by a [=template list=].

Ignoring [=comments=] and [=blankspace=], a <dfn noexport>template list</dfn> is:
* An initial `'<'` (U+003C) code point, then
* A [=syntax_sym/comma=]-separated list of one or more <dfn noexport>template parameters</dfn>, then
* An optional trailing [=syntax_sym/comma=], then
* A terminating `'>'` (U+003E) code point.

The form of a [=template parameter=] is implicitly defined by the [=template list discovery=] algorithm below.
Generally, they are names, expressions, or types.

Note: For example, the phrase `vec3<f32>` is a template parameterization where `vec3` is the general concept being modified,
and `<f32>` is a template list containing one parameter, the [=f32=] type.
Together, `vec3<f32>` denotes a specific [=vector=] type.

Note: For example, the phrase `var<storage,read_write>` modifies the general `var` concept with template parameters `storage` and `read_write`.

<div class=note>
<span class=marker>Note:</span>For example, the phrase `array<vec4<f32>>` has two template parameterizations:
* `vec4<f32>` modifies the general `vec4` concept with template parameter `f32`.
* `array<vec4<f32>>` modifies the general `array` concept with template parameter `vec4<f32>`.

</div>

The `'<'` (U+003C) and `'>'` (U+003E) code points that delimit a template list are also used when spelling:
* A comparison operator in a [=syntax/relational_expression=].
* A shift operator in a [=syntax/shift_expression=].
* A [=syntax/compound_assignment_operator=] for performing a shift operation followed by an assignment.

The syntactic ambiguity is resolved in favour of template lists:
* Template lists are discovered in an early phase of parsing, before [=declarations=], [=expressions=], [=statements=] are parsed.
* During tokenization in a later phase,
    the intial `'<'` (U+003C) of a template list is mapped to a [=syntax_sym/_template_args_start=] token, and
    the terminating `'>'` (U+003E) of a template list is mapped to a [=syntax_sym/_template_args_end=] token.


The [=template list discovery=] algorithm is given below.
It uses the following assumptions and properties:
1. A [=template parameter=] is an [=expression=], and therefore does not start with either a `'<'` (U+003C) or a `'='` (U+003D) code point.
2. An expression does not contain code points `';'` (U+003B), `'{'` (U+007B), or `':'` (U+003A).
3. An expression does not contain an [=statement/assignment=].
4. The only time a `'='` (U+003D) code point appears is as part of a comparison operation, i.e.
    in one of
    <a for=syntax_sym lt=less_than_equal>`'<='`</a>,
    <a for=syntax_sym lt=greater_than_equal>`'>='`</a>,
    <a for=syntax_sym lt=equal_equal>`'=='`</a>, or
    <a for=syntax_sym lt=not_equal>`'!='`</a>.
    Otherwise, a `'='` (U+003D) code point appears as part of an assignment.
5. Template list delimiters respect nested expressions formed by parentheses '(...)', and array indexing '[...]'.
    The start and end of a template list must appear at the same nesting level.

<blockquote algorithm="template list discovery">
**Algorithm:** <dfn noexport>Template list discovery</dfn>

**Input:** The program source text.

**Record types:**

Let |UnclosedCandidate| be a record type containing:
    * |position|, a location in the source text
    * |depth|, an integer, the expression nesting depth at |position|

Let |TemplateList| be a record type containing:
    * |start_position|, the source location of the `'<'` (U+003C) code point that starts this template list.
    * |end_position|, the source location of the `'>'` (U+003E) code point that ends this template list.

**Output:** |DiscoveredTemplateLists|, a list of |TemplateList| records.

**Algorithm:**
* Initialize |DiscoveredTemplateLists| to an empty list.
* Initialize a |Pending| variable to be an empty stack of |UnclosedCandidate| records.
* Initialize a |CurrentPosition| integer variable to 0.
    It encodes the position of the code point currently being examined, as a count of the number of code points after the start of the source text.
    * This variable will advance forward in the text while executing the algorithm.
          When the end of text is reached, terminate the algorithm immediately and have it return |DiscoveredTemplateLists|.
* Initialize a |NestingDepth| integer variable to 0.
* Repeat the following steps:
    * Advance |CurrentPosition| past [=blankspace=], [=comments=], and [=literals=].
    * If [=syntax/ident_pattern_token=] matches the text at |CurrentPosition|, then:
        * Advance |CurrentPosition| past the [=syntax/ident_pattern_token=].
        * Advance |CurrentPosition| past blankspace and comments, if present.
        * If `'<'` (U+003C) appears at |CurrentPosition|, then:
            * Note: This code point is a candidate for being the start of a template list.
                Save enough state so it can be matched against a terminating `'>'` (U+003E) appearing later in the input.
            * Push |UnclosedCandidate|(|position|=|CurrentPosition|,|depth|=|NestingDepth|) onto the |Pending| stack.
            * Advance |CurrentPosition| to the next code point.
            * If `'<'` (U+003C) appears at |CurrentPosition|, then:
                * Note: From assumption 1, no template parameter starts with `'<'` (U+003C), so the previous code point cannot be the start of a template list.
                    Therefore the current and previous code point must be <a for=syntax_sym lt=shift_left>`'<<'`</a> operator.
                * Pop the top entry from the |Pending| stack.
                * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
            * If `'='` (U+003D) appears at |CurrentPosition|, then:
                * Note: From assumption 1, no template parameter starts with `'='` (U+003C), so the previous code point cannot be the start of a template list.
                    Assume the current and previous code point form a <a for=syntax_sym lt=less_than_equal>`'<='`</a> comparison operator.
                    Skip over the `'='` (U+003D) code point so a later step does not mistake it for an assignment.
                * Pop the top entry from the |Pending| stack.
                * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
    * If `'>'` (U+003E) appears at |CurrentPosition| then:
        * Note: This code point is a candidate for being the end of a template list.
        * If |Pending| is not empty, then let |T| be its top entry, and if |T|.|depth| equals |NestingDepth| then:
            * Note: This code point ends the current template list whose start is recorded in |T|.
            * Add |TemplateList|(|start_position|=|T|.|position|, |end_position|=|CurrentPosition|) to |DiscoveredTemplateLists|.
            * Pop |T| off the |Pending| stack.
            * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
        * Otherwise, this code point does not end a template list:
            * Advance |CurrentPosition| past this code point.
            * If `'='` (U+003D) appears at |CurrentPosition| then:
                * Note: Assume the current and previous code points form a <a for=syntax_sym lt=greater_than_equal>`'>='`</a> comparison operator.
                    Skip over the `'='` (U+003D) code point so a later step does not mistake it for an assignment.
                * Advance |CurrentPosition| past this code point.
            * Start the next iteration of the loop.
    * If `'('` (U+0028) or `'['` (U+005B) appears at |CurrentPosition| then:
        * Note: Enter a nested expression.
        * Add 1 to |NestingDepth|.
        * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
    * If `')'` (U+0029) or `']'` (U+005D) appears at |CurrentPosition| then:
        * Note: Exit a nested expression.
        * Pop entries from the |Pending| stack until it is empty, or until the its top entry has |depth| &lt; |NestingDepth|.
        * Set |NestingDepth| to 0 or |NestingDepth| &minus; 1, whichever is larger.
        * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
    * If `'!'` (U+0021) appears at |CurrentPosition| then:
        * Advance |CurrentPosition| past this code point.
        * If `'='` (U+003D) appears at |CurrentPosition| then:
            * Note: Assume the current and previous code points form a <a for=syntax_sym lt=not_equal>`'!='`</a> comparison operator.
                Skip over the `'='` (U+003D) code point so a later step does not mistake it for an assignment.
            * Advance |CurrentPosition| past this code point.
        * Start the next iteration of the loop.
    * If `'='` (U+003D) appears at |CurrentPosition| then:
        * Advance |CurrentPosition| past this code point.
        * If `'='` (U+003D) appears at |CurrentPosition| then:
            * Note: Assume the current and previous code points form a <a for=syntax_sym lt=equal_equal>`'=='`</a> comparison operator.
                Skip over the `'='` (U+003D) code point so a later step does not mistake it for an assignment.
            * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
        * Note: Assume this code point is part of an assignment, which cannot appear as part of an expression, and therefore cannot appear in a template list.
             Clear pending unclosed candidates.
        * Set |NestingDepth| to 0.
        * Remove all entries from the |Pending| stack.
        * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
    * If `';'` (U+003B) or `'{'` (U+007B) or `':'` (U+003A) appears at |CurrentPosition| then:
        * Note: These cannot appear in the middle of an expression, and therefore cannot appear in a template list.
             Clear pending unclosed candidates.
        * Set |NestingDepth| to 0.
        * Remove all entries from the |Pending| stack.
        * Advance |CurrentPosition| past this code point, and start the next iteration of the loop.
    * If <a for=syntax_sym lt=and_and>`'&&'`</a> or <a for=syntax_sym lt=or_or>`'||'`</a> matches the text at |CurrentPosition| then:
        * Note: These are operators that have lower precedence than comparisons.  Reject any pending unclosed candidates at the current expression level.
        * Note: With this rule, no template list will be found in the program fragment `a<b || c>d`.
             Instead it will be recognized as the short-circuiting disjunction of two comparisons.
        * Pop entries from the |Pending| stack until it is empty, or until the its top entry has |depth| &lt; |NestingDepth|.
        * Advance |CurrentPosition| past the two code points, and start the next iteration of the loop.
    * Advance |CurrentPosition| past the current code point.

</blockquote>

<div class=note algorithm="find template parameters">
<span class=marker>Note:</span>The algorithm can be modified to find the source ranges for [=template parameters=], as follows:

* Modify |UnclosedCandidate| to add the following fields:
    *  |parameters|, a list of source ranges of template parameters.
    *  |parameter_start_position|, a source location.
* Modify |TemplateList| to add a field:
    *  |parameters|, a list of source ranges of template parameters.
* When pushing a new |UnclosedCandidate| onto the |Pending| stack:
    * Set its |parameters| field to an empty list.
    * Set |parameter_start_position| to one code point past |CurrentPosition|.
* When adding a |TemplateList|, |TL|, to <var ignore>DiscoveredTemplateLists</var>:
    * Let |T| be the top of the |Pending| stack, as in the original algorithm.
    * Push the source range starting at |T|.|parameter_start_position| and ending at |CurrentPosition|&minus;1 onto |T|.|parameters|.
    * Prepare |TL| as in the original algorithm.
    * Set |TL|.|parameters| to |T|.|parameters|.
* Insert a check at the end the loop, just before advancing past the current code point:
    * If '`,`' (U+002C) appears at |CurrentPosition| and |Pending| is not empty, then:
        * Let |T| be the top of the |Pending| stack.
        * Push the source range starting at |T|.|parameter_start_position| and ending at |CurrentPosition|&minus;1 onto |T|.|parameters|.
        * Set |T|.|parameter_start_position| to |CurrentPosition|&plus;1

</div>

Note: The algorithm explicitly skips past literals because some numeric literals end in a letter, for example `1.0f`.
The terminating `f` should not be mistaken as the start of an [=syntax/ident_pattern_token=].

Note: In the phrase `A ( B < C, D > ( E ) )`, the segment `< C, D >` is a [=template list=].

Note: The algorithm respects expression nesting: The start and end of a particular template list cannot appear at different expression nesting levels.
For example, in `array<i32,select(2,3,a>b)>`, the template list has three parameters, where the last one is `select(2,3,a>b)`.
The `'>'` in `a>b` does not terminate the template list because it is enclosed in a parenthesized part of the expression calling the `select` function.

Note: Both ends of a template list must appear within the same [=indexing expression=]. For example `a[b<d]>()` does not contain a valid template list.

Note: In the phrase `A<B<<C>`, the phrase `B<<C` is parsed as `B` followed by the left-shift operator <a for=syntax_sym lt=shift_left>`'<<'`</a> followed by `C`.
The template discovery algorithm starts examining `B` then '`<`' (U+003C) but then sees that the next `'<'` (U+003C) code point cannot start a template argument, and so
the `'<'` immediately after the `B` is not the start of a template list.
The initial `'<'` and final `'>'` are the only template list delimiters, and it has template parameter `B<<C`.

Note: The phrase `A<B<=C>` is analyzed similarly to the previous note, so the phrase `B<=C` is parsed as `B` followed by the less-than-or-equal operator <a for=syntax_sym lt=less_than_equal>`'<='`</a> followed by `C`.
The template discovery algorithm starts examining `B` then `'<'` (U+003C) but then sees that the next `'='` (U+003D) code point cannot start a template argument, and so
the `'<'` immediately after the `B` is not the start of a template list.
The initial `'<'` and final `'>'` are the only template list delimiters, and it has template parameter `B<=C`.

Note: When examining the phrase `A<(B>=C)>`, there is one template list, starting at the first `'<'` (U+003C) code point and ending at the last `'>'` (U+003E) code point, and having template argument `B>=C`.
After examining the first `'>'` (U+003C) code point (after `B`), the `'='` (U+003D) code point needs to be recognized specially so it isn't assumed to be part of an assignment.

Note: When examining the phrase `A<(B!=C)>`, there is one template list, starting at the first `'<`' (U+003C) code point and ending at the last `'>'` (U+003E) code point, and having template argument `B!=C`.
After examining the `'!'` (U+0021) code point (after `'B'`), the `'='` (U+003D) code point needs to be recognized specially so it isn't assumed to be part of an assignment.

Note: When examining the phrase `A<(B==C)>`, there is one template list, starting at the first `'<'` (U+003C) code point and ending at the last `'>'` (U+003E) code point, and having template argument `B==C`.
After examining the first `'='` (U+003D) code point (after `'B'`), the second `'='` (U+003D) code point needs to be recognized specially so neither are assumed to be part of an assignment.

After [=template list discovery=] completes,
[[#parsing|parsing]] [=behavioral requirement|will=] attempt to match each template list to the [=syntax/template_list=] grammar rule.

<pre class=include>
path: syntax/template_list.syntax.bs.include
</pre>

<pre class=include>
path: syntax/template_arg_comma_list.syntax.bs.include
</pre>

<pre class=include>
path: syntax/template_arg_expression.syntax.bs.include
</pre>

# Directives # {#directives}

A <dfn noexport>directive</dfn> is a [=token=] sequence which modifies how a WGSL
program is processed by a WebGPU implementation.

Directives are optional.
If present, all directives [=shader-creation error|must=] appear before any [=declarations=] or [[#const-assert-statement|const assertions]].

<pre class=include>
path: syntax/global_directive.syntax.bs.include
</pre>

## Extensions ## {#extensions}

WGSL is expected to evolve over time.

An <dfn noexport>extension</dfn> is a named grouping of a coherent
set of modifications to the WGSL specification, consisting of any combination of:
* Addition of new concepts and behaviors via new syntax, including:
    * declarations, statements, attributes, and built-in functions.
* Removal of restrictions in the current specification or in previously published extensions.
* Syntax for reducing the set of permissible behaviors.
* Syntax for limiting the features available to a part of the program.
* A description of how the extension interacts with the existing specification, and optionally with other extensions.

Hypothetically, extensions could:
* Add numeric scalar types, such as different bit width integers.
* Add syntax to constrain floating point rounding mode.
* Add syntax to signal that a shader does not use atomic types.
* Add new kinds of statements.
* Add new built-in functions.
* Add syntax to constrain how shader invocations execute.
* Add new shader stages.

There are two kinds of extensions: [=enable-extensions=] and [=language extensions=].

### Enable Extensions ### {#enable-extensions-sec}

An <dfn noexport>enable-extension</dfn> is an [=extension=] whose functionality is available only if:
* The implementation supports it, and
* The shader explicitly requests it via an [=enable directive=], and
* The corresponding WebGPU {{GPUFeatureName}} was one of the required features requested when creating the {{GPUDevice}}.

[=Enable-extensions=] are intended to expose hardware functionality that is not universally available.

An <dfn noexport>enable directive</dfn> is a [=directive=] that turns on support for one or more enable-extensions.
A [=shader-creation error=] results if the implementation does not support all the listed enable-extensions.

<pre class=include>
path: syntax/enable_directive.syntax.bs.include
</pre>
<pre class=include>
path: syntax/enable_extension_list.syntax.bs.include
</pre>

Like other directives, if an [=enable directive=] is present, it must appear before all [=declarations=] and [[#const-assert-statement|const assertions]].
Extension names are not [=identifiers=]: they do not [=resolve=] to [=declarations=].

The valid [=enable-extensions=] are listed in the following table.
<table class='data'>
  <caption>Enable-extensions</caption>
  <thead>
    <tr><th>WGSL enable-extension
        <th>WebGPU {{GPUFeatureName}}
        <th>Description
  </thead>
  <tr><td><dfn noexport dfn-for="extension">`f16`</dfn>
      <td>[[WebGPU#shader-f16|"shader-f16"]]
      <td>The [=f16=] type is valid to use in the WGSL module. Otherwise, using [=f16=] (directly or indirectly) will result in a [=shader-creation error=].
  <tr><td><dfn noexport dfn-for="extension">`clip_distances`</dfn>
      <td>[[WebGPU#dom-gpufeaturename-clip-distances|"clip-distances"]]
      <td>The built-in variable [=built-in values/clip_distances=] is valid to use in the WGSL
          module. Otherwise, using [=built-in values/clip_distances=] will result in a
          [=shader-creation error=].
  <tr><td><dfn noexport dfn-for="extension">`dual_source_blending`</dfn>
      <td>[[WebGPU#dom-gpufeaturename-dual-source-blending|"dual-source-blending"]]
      <td>The attribute [=attribute/blend_src=] is valid to use in the WGSL module. Otherwise, using
          [=attribute/blend_src=] will result in a [=shader-creation error=].
</table>

<div class='example wgsl using extensions expect-error' heading="Using hypothetical enable-extensions">
  <xmp highlight=wgsl>
    // Enable a hypothetical extension for arbitrary precision floating point types.
    enable arbitrary_precision_float;
    enable arbitrary_precision_float; // A redundant enable directive is ok.

    // Enable a hypothetical extension to control the rounding mode.
    enable rounding_mode;

    // Assuming arbitrary_precision_float enables use of:
    //    - a type f<E,M>
    //    - as a type in function return, formal parameters and let-declarations
    //    - as a value constructor from AbstractFloat
    //    - operands to division operator: /
    // Assuming @rounding_mode attribute is enabled by the rounding_mode enable directive.
    @rounding_mode(round_to_even)
    fn halve_it(x : f<8, 7>) -> f<8, 7> {
      let two = f<8, 7>(2);
      return x / 2; // uses round to even rounding mode.
    }
  </xmp>
</div>

### Language Extensions ### {#language-extensions-sec}

A <dfn noexport>language extension</dfn> is an [=extension=] which is automatically available if the implementation supports it.
The program does not have to explicitly request it.

[=Language extensions=] embody functionality which could reasonably be supported on any WebGPU implementation.
If the feature is not universally available, that it is because some WebGPU implementation has not yet implemented it.

Note: For example, do-while loops could be a language extension.

The {{GPU/wgslLanguageFeatures}} member of the WebGPU {{GPU}} object lists the set of
[=language extensions=] supported by the implementation.

A <dfn noexport>requires-directive</dfn> is a [=directive=] that *documents* the program's use of one or more [=language extensions=].
It does not change the functionality exposed by the implementation.
A [=shader-creation error=] results if the implementation does not support one of the required extensions.

A WGSL module *can* use a [=requires-directive=] to signal the potential for non-portability,
and to signal the *intended* minimum bar for portability.

Note: Tooling outside of a WebGPU implementation could check whether all the [=language extensions=] used by a
program are covered by [=requires-directives=] in the program.

<pre class=include>
path: syntax/requires_directive.syntax.bs.include
</pre>
<pre class=include>
path: syntax/software_extension_list.syntax.bs.include
</pre>

Like other directives, if a [=requires-directive=] is present, it must appear before all [=declarations=] and [[#const-assert-statement|const assertions]].
Extension names are not [=identifiers=]: they do not [=resolves|resolve=] to [=declarations=].

<table class='data'>
  <caption>Language extensions</caption>
  <thead>
    <tr><th style="width:30%">WGSL language extension
        <th>Description
  </thead>
  <tr><td><dfn for="language_extension">readonly_and_readwrite_storage_textures</dfn>
      <td>Allows the use of [=access/read=] and [=access/read_write=] [=access modes=]
      with [=type/storage textures=].
      Additionally, adds the [[#textureBarrier-builtin|textureBarrier]] built-in function.
  <tr><td><dfn for="language_extension">packed_4x8_integer_dot_product</dfn>
      <td>
      Supports using 32-bit integer scalars packing 4-component vectors of 8-bit integers as inputs
      to the dot product instructions with [[#dot4U8Packed-builtin|dot4U8Packed]] and
      [[#dot4I8Packed-builtin|dot4I8Packed]] built-in functions.
      Additionally, adds packing and unpacking instructions with packed 4-component vectors of
      8-bit integers with [[#pack4xI8-builtin|pack4xI8]], [[#pack4xU8-builtin|pack4xU8]],
      [[#pack4xI8Clamp-builtin|pack4xI8Clamp]], [[#pack4xU8Clamp-builtin|pack4xU8Clamp]],
      [[#unpack4xI8-builtin|unpack4xI8]], and [[#unpack4xU8-builtin|unpack4xU8]] built-in functions.
  <tr><td><dfn for="language_extension">unrestricted_pointer_parameters</dfn>
      <td>
      Removes the following [[#function-restriction|restrictions]] from [=user-defined functions=]:

      For [=user-defined functions=], a parameter of pointer type
      [=shader-creation error|must=] be in one of the following address spaces:
      * [=address spaces/function=]
      * [=address spaces/private=]

      Each argument of pointer type to a [=user-defined function=]
      [=shader-creation error|must=] have the same [=memory view=] as its
      [=root identifier=].
      * NOTE: This means no [=vector=], [=matrix=], [=array=], or [=struct=] access expressions
          can be applied to produce a [=memory view=] into the [=root identifier=] when
          traced from the argument back through all the [=let-declarations=].
  <tr><td><dfn for="language_extension">pointer_composite_access</dfn>
      <td>
      Supports [[#composite-value-decomposition-expr|composite-value
      decomposition expressions]] where the root expression is a pointer,
      yielding a reference.

      For example, if `p` is a pointer to a structure with member `m`, then
      `p.m` is a reference to the memory locations for `m` inside the structure
      `p` points to.

      Similarly, if `pa` is a pointer to an array, then `pa[i]` is a reference
      to the memory locations for the `i`'th element of the array `pa` points
      to.
</table>

Note: The intent is that, over time, WGSL will define language extensions embodying all functionality in language extensions commonly supported at that time.
In a [=requires-directive=], these serve as a shorthand for listing all those common features.
They represent progressively increasing sets of functionality, and can be thought of as language versions, of a sort.

## Global Diagnostic Filter ## {#global-diagnostic-directive}

A <dfn noexport>global diagnostic filter</dfn> is a diagnostic filter whose [=affected range=] is the whole WGSL module.
It is a [=directive=], thus appearing before any [=module scope|module-scope=] declarations.
It is spelled like the attribute form, but without the leading `@` (U+0040) code point, and with a terminating semicolon.

<pre class=include>
path: syntax/diagnostic_directive.syntax.bs.include
</pre>

# Declaration and Scope # {#declaration-and-scope}

A <dfn noexport>declaration</dfn> associates an [=identifier=] with one of
the following kinds of objects:
* a [=type=]
* a [=type-generator=]
* a [=value declaration|value=]
* a [=variable=]
* a [=function/function=]
* a [=formal parameter=]
* an [=enumerant=]

In other words, a declaration introduces a <dfn noexport>name</dfn> for an object.

A declaration is at <dfn noexport>module scope</dfn> if the declaration appears
in the program source, but outside the text of any other declaration.

A [=function/function=] declaration appears at module-scope.
A function declaration contains declarations for formal parameters, if it has any,
and it may contain [[#var-and-value|variable and value declarations]] inside its [=function body|body=].
Those contained declarations are therefore not at module-scope.

Note: The only kind of declaration that contain another declaration is a [=function declaration=].

Certain objects are provided by the WebGPU implementation, and are treated as
if they have been declared before the start of the WGSL module source.
We say such objects are <dfn noexport>predeclared</dfn>.
For example, WGSL predeclares:
* [=built-in functions=],
* built-in types such as [=i32=] and [=f32=],
* built-in [=type-generators=] such as `array`, `ptr`, and `texture_2d`, and
* [=enumerants=] such as [=access/read_write=], [=address spaces/workgroup=], and [=texel format/rgba8unorm=].

The <dfn noexport>scope</dfn> of a declaration is the set of
program source locations where a declared identifier potentially denotes
its associated object.
We say the identifier is <dfn noexport>in scope</dfn>
(of the declaration) at those source locations.

Where a declaration appears determines its scope:
* Predeclared objects, and objects declared at module-scope, are [=in scope=] across the entire program source.
* Each [=formal parameter=] of a user-declared function is [=in scope=] across the corresponding [=function body=].
    See [[#function-declaration-sec]].
* Otherwise, the scope is a span of text beginning immediately after the end of the declaration.
    For details, see [[#var-and-value]].

Two declarations in the same WGSL source program [=shader-creation error|must not=] simultaneously:
* introduce the same identifier name, and
* have the same end-of-scope.

Note: A predeclared object does not have a declaration in the WGSL source.
So a user-specified declaration at module-scope or inside a function can have the same name as a predeclared object.

Identifiers are used as follows, distinguished by grammatical context:
* A token matching the [=syntax/ident=] grammar element is:
    * Used in a [=declaration=], as the name of the object being declared, or
    * Used as a name, denoting an object declared elsewhere.  This is the common case.
* A token matching the [=syntax/member_ident=] grammar element is:
    * Used in a [=structure=] type [=declaration=], as the name of a [=member=], or
    * Used as a name, denoting a member of a structure value, or denoting a reference to a member of a structure. See [[#struct-access-expr]].

When an [=syntax/ident=] token appears as a name denoting an object declared elsewhere,
it [=shader-creation error|must=] be [=in scope=] for some declaration.
The object denoted by the identifier token is determined as follows:
* If the token is in scope for at least one non-[=module scope|module-scope=] declaration,
    then the token denotes the object associated with the nearest of those declarations.

    Note: The nearest such declaration appears before the identifier token.

* Otherwise, if there is a module-scope declaration with that name, then the token
    denotes that declared object.

    Note: The module-scope declaration may appear before **or after** the identifier token.

* Otherwise, if there is a [=predeclared=] object with that name, then the token denotes that object.

When the above algorithm is used to map an identifier to a declaration, we
say the identifier <dfn noexport>resolves</dfn> to that declaration.
Similarly, we also say the identifier [=resolves=] to the declared object.

It is a [=shader-creation error=] if any [=module scope=] declaration is recursive.
That is, no cycles can exist among the declarations:

> Consider the directed graph where:
> * Each node corresponds to a declaration |D|.
> * There is an edge from declaration |D| to declaration |T| when the definition
>      for |D| mentions an identifier which [=resolves=] to |T|.
>
> This graph must not have a cycle.

Note: The [=function body=] is part of the [=function declaration=], thus
functions must not be recursive, either directly or indirectly.

Note: Non-[=module scope=] identifier declarations must precede their uses in
the text.

<div class='example wgsl' heading='Valid and invalid declarations'>
  <xmp highlight=wgsl>
    // Valid, user-defined variables can have the same name as a built-in function.
    var<private> modf: f32 = 0.0;

    // Valid, foo_1 is in scope for the entire program.
    var<private> foo: f32 = 0.0; // foo_1

    // Valid, bar_1 is in scope for the entire program.
    var<private> bar: u32 = 0u; // bar_1

    // Valid, my_func_1 is in scope for the entire program.
    // Valid, foo_2 is in scope until the end of the function.
    fn my_func(foo: f32) { // my_func_1, foo_2
      // Any reference to 'foo' resolves to the function parameter.

      // Invalid, modf resolves to the module-scope variable.
      let res = modf(foo);

      // Invalid, the scope of foo_2 ends at the of the function.
      var foo: f32; // foo_3

      // Valid, bar_2 is in scope until the end of the function.
      var bar: u32; // bar_2
      // References to 'bar' resolve to bar_2
      {
        // Valid, foo_4 is in scope until the end of the compound statement.
        var foo : f32; // foo_4

        // Valid, bar_3 is in scope until the end of the compound statement.
        var bar: u32; // bar_3
        // References to 'bar' resolve to bar_3

        // Invalid, bar_4 has the same end scope as bar_3.
        var bar: i32; // bar_4

        // Valid, i_1 is in scope until the end of the for loop
        for ( var i: i32 = 0; i < 10; i++ ) { // i_1
          // Invalid, i_2 has the same end scope as i_1.
          var i: i32 = 1; // i_2.
        }
      }

      // Invalid, bar_5 has the same end scope as bar_2.
      var bar: u32; // bar_5

      // Valid, later_def, a module scope declaration, is in scope for the entire program.
      var early_use : i32 = later_def;
    }

    // Invalid, bar_6 has the same scope as bar_1.
    var<private> bar: u32 = 1u; // bar_6

    // Invalid, my_func_2 has the same end scope as my_func_1.
    fn my_func() { } // my_func_2

    // Valid, my_foo_1 is in scope for the entire program.
    fn my_foo( //my_foo_1
      // Valid, my_foo_2 is in scope until the end of the function.
      my_foo: i32 // my_foo_2
    ) { }

    var<private> later_def : i32 = 1;
  </xmp>
</div>

<div class='example wgsl' heading='Shadowing predeclared objects'>
  <xmp highlight=wgsl>
     // This declaration hides the predeclared 'min' built-in function.
     // Since this declaration is at module-scope, it is in scope over the entire
     // source.  The built-in function is no longer accessible.
     fn min() -> u32 { return 0; }

     const rgba8unorm = 12; // This shadows the predeclared 'rgba8unorm' enumerant.
  </xmp>
</div>

# Types # {#types}

Programs calculate values.

In WGSL, a <dfn noexport>type</dfn> is a set of values, and each value belongs to exactly one type.
A value's type determines the syntax and semantics of operations that can be performed on that value.

For example, the mathematical number 1 corresponds to these distinct values in WGSL:
* the 32-bit signed integer value `1i`,
* the 32-bit unsigned integer value `1u`,
* the 32-bit floating point value `1.0f`,
* the 16-bit floating point value `1.0h` if the [=extension/f16|f16 extension=] is enabled,
* the [=AbstractInt=] value 1, and
* the [=AbstractFloat=] value 1.0

WGSL treats these as different because their machine representation and operations differ.

A type is either [=predeclared=], or created in WGSL source via a [=declaration=].

Some types are expressed as [=template parameterizations=].
A <dfn noexport>type-generator</dfn> is a [=predeclared=] object which, when parameterized with a [=template list=], denotes a type.
For example, the type `atomic<u32>` combines the type-generator `atomic` with template list `<u32>`.

We distinguish between the *concept* of a type and the *syntax* in WGSL to denote that type.
In many cases the spelling of a type in this specification is the same as its WGSL syntax.
For example:
* the set of 32-bit unsigned integer values is spelled `u32` in this specification,
    and also in a WGSL module.
* the spelling is different for structure types, or types containing structures.

Some WGSL types are only used for analyzing a source program and
for determining the program's runtime behavior.
This specification will describe such types, but they do not appear in WGSL source text.

Note: [=Reference types=] are not written in WGSL modules. See [[#ref-ptr-types]].

## Type Checking ## {#type-checking-section}

A WGSL value is computed by evaluating an expression.
An <dfn noexport>expression</dfn> is a segment of source text
parsed as one of the WGSL grammar rules whose name ends with "`expression`".
An expression |E| can contain <dfn noexport>subexpressions</dfn> which are expressions properly contained
in the outer expression |E|.
A <dfn noexport>top-level expression</dfn> is an expression that is not itself a subexpression.
See [[#expression-grammar]].

The particular value produced by an expression evaluation depends on:
* <dfn noexport>static context</dfn>:
    the source text surrounding the expression, and
* <dfn noexport>dynamic context</dfn>:
    the state of the invocation evaluating the expression,
    and the execution context in which the invocation is running.

The values that may result from evaluating a particular expression will always belong to a specific WGSL type,
known as the <dfn noexport>static type</dfn> of the expression.
The rules of WGSL are designed so that the static type of an expression depends
only on the expression's [=static context=].


A <dfn noexport>type assertion</dfn> is a mapping from some WGSL source expression to a WGSL type.
The notation

> *e* : *T*

is a type assertion meaning *T* is the static type of WGSL expression *e*.

Note: A type assertion is a statement of fact about the text of a program.
It is not a runtime check.

Statements often use expressions, and may place requirements on the static types of those expressions.
For example:
* The condition expression of an `if` statement [=shader-creation error|must=] be of type [=bool=].
* In a `let` declaration with an explicit type specified, the initializer
      expression [=shader-creation error|must=] evaluate to that type.

<dfn noexport>Type checking</dfn> a successfully parsed WGSL module is the process of mapping
each expression to its static type,
and verifying that type requirements of each statement are satisfied.
If type checking fails, a special case of a [=shader-creation error=], called a <dfn noexport>type error</dfn>, results.

Type checking can be performed by recursively applying [=type rules=]
to syntactic phrases, where a <dfn noexport>syntactic phrase</dfn> is either an [=expression=] or a [[#statements|statement]].
A <dfn noexport>type rule</dfn> describes how the [=static context=] for a [=syntactic phrase=]
determines the static type for expressions contained within that phrase.
A [=type rule=] has two parts:
* A <dfn noexport lt="type rule conclusion">conclusion</dfn>.
    * If the phrase is an expression, the conclusion is a [=type assertion=] for the expression.
    * If the phrase is a statement, the conclusion is a set of [=type assertions=],
        one for each of the statement's [=top-level expressions=].
    * In both cases, the [=syntactic phrases=] are specified schematically,
        using *italicized* names to denote subexpressions
        or other syntactically-determined parameters.
* <dfn noexport lt="type rule preconditions">Preconditions</dfn>, consisting of:
    * For expressions:
        * Type assertions for subexpressions, when it has subexpressions.
             Each may be satisfied directly, or via a [=feasible automatic conversion=] (as defined in [[#conversion-rank]]).
             WGSL [=behavioral requirement|will=] evaluate all [=const-expressions=] required
             to determine the [=static types=] of a program.
        * How the expression is used in a statement.
    * For statements:
        * The syntactic form of the statement, and
        * Type assertions for [=top-level expressions=] in the statement.
    * Conditions on the other schematic parameters, if any.
    * Optionally, other static context.

Type rules may have <dfn noexport>type parameters</dfn> in their preconditions and conclusions.
When a type rule's conclusion or preconditions contain type parameters,
we say it is <dfn noexport>parameterized</dfn>.
When they do not, we say the rule is <dfn noexport>fully elaborated</dfn>.
We can make a fully elaborated type rule from a parameterized one
by substituting a type for each of its type parameters,
using the same type for all occurrences of a given parameter in the rule.
An assignment of types to a rule's type parameters
is called a <dfn noexport>substitution</dfn>.

For example, here is the type rule for [[#logical-expr|logical negation]]
(an expression of the form `!`|e|):

<table class='data'>
  <thead>
    <tr><th>Precondition<th>Conclusion
  </thead>
  <tr algorithm="example boolean negation"><td>|e|: |T|<br>
  |T| is bool or vec|N|&lt;bool&gt;
  <td>`!`|e|`:` |T|
</table>

This is a parameterized rule, because it contains the type parameter |T|,
which can represent any one of four types
[=bool=], `vec2<bool>`, `vec3<bool>`, or `vec4<bool>`.
Applying the substitution that maps |T| to `vec3<bool>`
produces the fully elaborated type rule:

<table class='data'>
  <thead>
    <tr><th>Precondition<th>Conclusion
  </thead>
  <tr algorithm="example2 boolean negation"><td>|e|`: vec3<bool>`<br>
  <td>`!`|e|`: vec3<bool>`
</table>

Each fully elaborated rule we can produce from a parameterized rule
by applying some substitution that meets the rule's other conditions
is called an <dfn noexport>overload</dfn> of the parameterized rule.
For example, the boolean negation rule has four overloads,
because there are four possible ways to assign a type to its type parameter |T|.

Note:
In other words, a parameterized type rule provides the pattern
for a collection of fully elaborated type rules,
each one produced by applying a different substitution to the parameterized rule.

A <dfn noexport>type rule applies to a syntactic phrase</dfn> when:
* The rule's conclusion matches a valid parse of the [=syntactic phrase=], and
* The rule's preconditions are satisfied.

A [=parameterized=] type rule applies to an expression
if there exists a [=substitution=] producing a [=fully elaborated=] type rule
that applies to the expression.

Consider the expression, `1u+2u`.
It has two [[#literal-expressions|literal subexpressions]]: `1u` and `2u`, both of type u32.
The [=top-level expression=] is an addition.
Referring to the rules in [[#arithmetic-expr]], the type rule for addition applies to the expression, because:
* `1u+2u` matches a parse of the form |e1|+|e2|, with |e1| standing for `1u` and |e2| standing for `2u`, and
* |e1| is of type u32, and
* |e2| is of type u32, and
* we can substitute u32 for the type parameter |T| in the type rule,
    resulting in a [=fully elaborated=] rule that applies to the entire expression.

When analyzing a [=syntactic phrase=], three cases may occur:
* No type rules apply to the expression.  This results in a [=type error=].
* Exactly one [=fully elaborated=] type rule applies to the expression.
    In this case, the rule's [=type rule conclusion|conclusion=] is asserted, determining the static type for the expression.
* More than one type rule applies. That is, the preconditions for more than one [=overload=] are satisfied.
    In this case the tie-breaking procedure described in [[#overload-resolution-section]] is used.
    * If overload resolution succeeds, a single [=overload=] is determined to apply to the expression.
        The [=type assertions=] in the [=type rule conclusion|conclusion=] for that overload are asserted,
        and therefore determine the types for the expression or expressions in the [=syntactic phrase=].
    * If overload resolution fails, a [=type error=] results.

Continuing the example above, only one type rule applies to the expression `1u+2u`, and so type checking
accepts the conclusion of that type rule, which is that `1u+2u` is of type u32.

A WGSL source program is <dfn noexport>well-typed</dfn> when:
* The static type can be determined for each expression in the program by applying the type rules, and
* The type requirements for each statement are satisfied.

Otherwise there is a [=type error=] and the source program is not a valid WGSL module.

WGSL is a <dfn noexport>statically typed language</dfn>
because type checking a WGSL module [=behavioral requirement|will=] either succeed or
discover a type error, while only having to inspect the program source text.

### Type Rule Tables ### {#typing-tables-section}

The WGSL [=type rules=] for expressions are organized into <dfn noexport>type rule tables</dfn>,
with one row per type rule.

The <dfn noexport>semantics of an expression</dfn> is the effect of evaluating that expression,
and is primarily the production of a result value.
The *Description* column of the type rule that applies to an expression will specify the expression's semantics.
The semantics usually depends on the values of the type rule parameters, including
the assumed values of any subexpressions.
Sometimes the semantics of an expression includes effects other than producing
a result value, such as the non-result-value effects of its subexpressions.

<div class='example' heading="Side-effect of an expression">
  <xmp highlight=wgsl>
    fn foo(p : ptr<function, i32>) -> i32 {
      let x = *p;
      *p += 1;
      return x;
    }

    fn bar() {
      var a: i32;
      let x = foo(&a); // the call to foo returns a value
                       // and updates the value of a
    }
  </xmp>
</div>

### Conversion Rank ### {#conversion-rank}

When a type assertion |e|:|T| is used as a [=type rule precondition=], it is satisfied when:
* |e| is already of type |T|, or
* |e| is of type |S|, and type |S| is [=feasible automatic conversion|automatically convertible=] to type |T|, as defined below.

The rule is codified by the <dfn>ConversionRank</dfn> function over pairs of types, defined in the table below.
The [=ConversionRank=] function expresses the preference and feasibility of automatically converting a value of one type (*Src*) to
another type (*Dest*).
Lower ranks are more desirable.

A <dfn>feasible automatic conversion</dfn> converts a value from type *Src* to type *Dest*, and is allowed when [=ConversionRank=](*Src*,*Dest*) is finite.
Such conversions are value-preserving, subject to limitations described in [[#floating-point-evaluation]].

Note: Automatic conversions only occur in two kinds of situations.
First, when converting a [=const-expression=] to its corresponding typed numeric value that can be used on the GPU.
Second, when a load from a reference-to-memory occurs, yielding the value stored in that memory.

Note: A conversion of infinite rank is infeasible, i.e. not allowed.

Note: When no conversion is performed, the conversion rank is zero.

<table class='data'>
  <caption>
    ConversionRank from one type to another
  </caption>
  <thead>
    <tr><th>Src
        <th>Dest
        <th>ConversionRank(Src,Dest)
        <th>Description
  </thead>
  <tr algorithm="conversion rank identity">
      <td>|T|
      <td>|T|
      <td>0
      <td>Identity. No conversion performed.
  <tr algorithm="conversion rank from reference via load rule">
      <td>ref&lt;|AS|,|T|,|AM|&gt;<br>for [=address space=] |AS|,
          and where [=access mode=] |AM| is [=access/read=] or [=access/read_write=].
      <td>|T|
      <td>0
      <td>Apply the [=Load Rule=] to load a value from a memory reference.
  <tr algorithm="conversion rank abstract float to f32">
      <td>[=AbstractFloat=]
      <td>f32
      <td>1
      <td>See [[#floating-point-conversion]]
  <tr algorithm="conversion rank abstract float to f16">
      <td>[=AbstractFloat=]
      <td>f16
      <td>2
      <td>See [[#floating-point-conversion]]
  <tr algorithm="conversion rank abstract int to i32">
      <td>[=AbstractInt=]
      <td>i32
      <td>3
      <td>Identity if the value is in [=i32=].
          Produces a [=shader-creation error=] otherwise.
  <tr algorithm="conversion rank abstract int to u32">
      <td>[=AbstractInt=]
      <td>u32
      <td>4
      <td>Identity if the value is in [=u32=].
          Produces a [=shader-creation error=] otherwise.
  <tr algorithm="conversion rank abstract int to abstract float">
      <td>[=AbstractInt=]
      <td>[=AbstractFloat=]
      <td>5
      <td>See [[#floating-point-conversion]]
  <tr algorithm="conversion rank abstract int to f32">
      <td>[=AbstractInt=]
      <td>f32
      <td>6
      <td>Behaves as [=AbstractInt=] to [=AbstractFloat=], and then [=AbstractFloat=] to f32
  <tr algorithm="conversion rank abstract int to f16">
      <td>[=AbstractInt=]
      <td>f16
      <td>7
      <td>Behaves as [=AbstractInt=] to [=AbstractFloat=], and then [=AbstractFloat=] to f16
  <tr algorithm="conversion rank abstract vector">
      <td>vec|N|&lt;|S|&gt;
      <td>vec|N|&lt;|T|&gt;
      <td>ConversionRank(|S|,|T|)
      <td>Inherit conversion rank from component type.
  <tr algorithm="conversion rank abstract matrix">
      <td>mat|C|x|R|&lt;|S|&gt;
      <td>mat|C|x|R|&lt;|T|&gt;
      <td>ConversionRank(|S|,|T|)
      <td>Inherit conversion rank from component type.
  <tr algorithm="conversion rank abstract array">
      <td>array&lt;|S|,|N|&gt;
      <td>array&lt;|T|,|N|&gt;
      <td>ConversionRank(|S|,|T|)
      <td>Inherit conversion rank from component type.
      Note: Only [=fixed-size arrays=] may have an [=type/abstract=] component type.
  <tr algorithm="conversion rank for frexp result">
      <td>__frexp_result_abstract
      <td>__frexp_result_f32
      <td>1
      <td>
  <tr algorithm="conversion rank for frexp result f16">
      <td>__frexp_result_abstract
      <td>__frexp_result_f16
      <td>2
      <td>
  <tr algorithm="conversion rank for frexp result vector">
      <td>__frexp_result_vecN_abstract
      <td>__frexp_result_vecN_f32
      <td>1
      <td>
  <tr algorithm="conversion rank for frexp result vector f16">
      <td>__frexp_result_vecN_abstract
      <td>__frexp_result_vecN_f16
      <td>2
      <td>
  <tr algorithm="conversion rank for modf result">
      <td>__modf_result_abstract
      <td>__modf_result_f32
      <td>1
      <td>
  <tr algorithm="conversion rank for modf result f16">
      <td>__modf_result_abstract
      <td>__modf_result_f16
      <td>2
      <td>
  <tr algorithm="conversion rank for modf result vector">
      <td>__modf_result_vecN_abstract
      <td>__modf_result_vecN_f32
      <td>1
      <td>
  <tr algorithm="conversion rank for modf result vector f16">
      <td>__modf_result_vecN_abstract
      <td>__modf_result_vecN_f16
      <td>2
      <td>
  <tr algorithm="conversion rank for non-convertible cases">
      <td><var ignore>S</var>
      <td><var ignore>T</var><br>where above cases don't apply
      <td>infinity
      <td>There are no automatic conversions between other types.
</table>

The type `T` is the <dfn noexport>concretization</dfn> of type `S` if:
* `T` is [=type/concrete=], and
* `T` is not a reference type, and
* ConversionRank(`S`, `T`) is finite, and
* For any other non-reference type `T2`, ConversionRank(`S`, `T2`) > ConversionRank(`S`, `T`).

The <dfn noexport>concretization of a value</dfn> `e` of type `T` is the value
resulting from applying, to `e`, the feasible conversion that maps `T` to the concretization of `T`.

Note: Conversion to [=f32=] is always preferred over [=f16=], therefore
automatic conversion will only ever produce an [=f16=] if
[=extension/f16|extension=] is enabled in the module.

### Overload Resolution ### {#overload-resolution-section}

When more than one [=type rule applies to a syntactic phrase=], a tie-breaking procedure is used
to determine which one should take effect.
This procedure is called <dfn noexport>overload resolution</dfn>,
and assumes type checking has already succeeded in finding static types for [=subexpressions=].

Consider a [=syntactic phrase=] |P|, and all [=type rule applies to a syntactic phrase|type rules that apply=] to |P|.
The overload resolution algorithm calls these type rules <dfn noexport>overload candidates</dfn>.
For each candidate:
* Its preconditions have been met either directly or through [=feasible automatic conversion|automatic conversion=].
* Its [=type rule conclusion|conclusion=] has:
    * A syntactic form matching a valid parse of |P|, and
    * A [=type assertion=] corresponding to each [=top-level expression=] in |P|.

Overload resolution for |P| proceeds as follows, with the goal of finding a single most [=preferable candidate|preferable=] [=overload candidate=]:

1. For each candidate |C|, enumerate conversion ranks for subexpressions in the syntactic phrase.
    The candidate's preconditions have been met, and so for the |i|'th subexpression in the |P|:
    * Its static type has been computed.
    * There is a [=feasible automatic conversion=] from the expression's static type to the type required by the corresponding type assertion in the preconditions.
        Let |C|.|R|(i) be the [=ConversionRank=] of that conversion.

1. Eliminate any candidate where one of its subexpressions resolves to an
    [=type/abstract=] type after [=feasible automatic conversions=], but another
    of the candidate's subexpressions is not a [=const-expression=].

    Note: As a consequence, if any subexpression in the phrase is not a [=const-expression=],
        then all subexpressions in the phrase must have a [=type/concrete=] type.

1. Rank candidates: Given two overload candidates |C1| and |C2|, |C1| is <dfn lt="preferable candidate">preferred</dfn> over |C2| if:
    * For each expression position |i| in |P|, |C1|.|R|(i) &le; |C2|.|R|(i).
         * That is, each expression conversion required to apply |C1| to |P| is at least as preferable as the corresponding expression conversion required to apply |C2| to |P|.
    * There is at least one expression position |i| where |C1|.|R|(i) &lt; |C2|.|R|(i).
         * That is, there is at least one expression conversion required to apply |C1| that is strictly more preferable than the corresponding conversion required to apply |C2|.

1. If there is a single candidate |C| which is [=preferable candidate|preferred=] over all the others, then overload resolution succeeds, yielding the candidate type rule |C|.
      Otherwise, overload resolution fails.

## Plain Types ## {#plain-types-section}

[=Plain types=] are types for the machine representation of boolean values, numbers, vectors,
matrices, or aggregations of such values.

A <dfn>plain type</dfn> is either a [=scalar=] type, an [=atomic type|atomic=]
type, or a [=composite=] type.

Note: Plain types in WGSL are similar to Plain-Old-Data types in C++, but also
include atomic types and abstract numeric types.

### Abstract Numeric Types ### {#abstract-types}

These types cannot be spelled in WGSL source. They are only used by [=type checking=].

Certain expressions are evaluated at [=shader module creation|shader-creation time=],
and with a numeric range and precision that may be larger than directly implemented by the GPU.

WGSL defines two <dfn>abstract numeric types</dfn> for these evaluations:
* The <dfn noexport>AbstractInt</dfn> type is the set of integers |i|, with -2<sup>63</sup> &leq; |i| &lt; 2<sup>63</sup>.
* The <dfn noexport>AbstractFloat</dfn> type is the set of finite floating point numbers representable
    in the [[!IEEE-754|IEEE-754]] binary64 (double precision) format.

An evaluation of an expression in one of these types [=shader-creation
error|must not=] overflow or produce an infinite or NaN value.

A type is <dfn dfn-for="type" noexport>abstract</dfn> if it is an abstract
numeric type or contains an abstract numeric type.
A type is <dfn dfn-for="type" noexport>concrete</dfn> if it is not abstract.

A [=numeric literal=] without a suffix denotes a value in an [=abstract numeric type=]:
* An [=integer literal=] without an `i` or `u` suffix denotes an [=AbstractInt=] value.
* A [=floating point literal=] without an `f` or `h` suffix denotes a [=AbstractFloat=] value.

Example:  The expression `log2(32)` is analyzed as follows:
* `log2(32)` is parsed as a function call to the `log2` builtin function with operand [=AbstractInt=] value 32.
* There is no overload of `log2` with an [=integer scalar=] formal parameter.
* Instead [=overload resolution=] applies, considering three possible overloads and [=feasible automatic conversions=]:
    * [=AbstractInt=] to [=AbstractFloat=]. (Conversion rank 4)
    * [=AbstractInt=] to [=f32=]. (Conversion rank 5)
    * [=AbstractInt=] to [=f16=]. (Conversion rank 6)
* The resulting computation occurs as an [=AbstractFloat=] (e.g. `log2(32.0)`).

Example:  The expression `1 + 2.5` is analyzed as follows:
* `1 + 2.5` is parsed as an addition operation with subexpressions [=AbstractInt=] value 1, and [=AbstractFloat=] value 2.5.
* There is no overload for |e|+|f| where |e| is integer type and |f| is floating point.
* However, using feasible automatic conversions, there are three potential overloads:
    * `1` is converted to [=AbstractFloat=] value `1.0` (rank 4) and `2.5` remains an [=AbstractFloat=] (rank 0).
    * `1` is converted to [=f32=] value `1.0f` (rank 5) and `2.5` is converted to [=f32=] value `2.5f` (rank 1).
    * `1` is converted to [=f16=] value `1.0f` (rank 6) and `2.5` is converted to [=f16=] value `2.5h` (rank 2).
* The first overload is the [=preferable candidate=] and type checking succeeds.
* The resulting computation occurs as an [=AbstractFloat=] `1.0 + 2.5`.

Example:  `let x = 1 + 2.5;`
* This example is similar to the above, except that `x` cannot resolve to an [=abstract numeric type=].
* Therefore, there are two viable overload candidates: addition using [=f32=] or [=f16=].
* The [=preferable candidate=] uses [=f32=].
* The effect of the declaration is as if it were written `let x : f32 = 1.0f + 2.5f;`.

Example:  `1u + 2.5` results in a [=shader-creation error=]:
* The `1u` term is an expression of type [=u32=].
* The `2.5` term is an expression of type [=AbstractFloat=].
* There are no valid overload candidates:
    * There is no feasible automatic conversion from a GPU-materialized [=integer scalar=] type to a floating point type.
    * No type rule matches *e*`+`*f* with *e* in an [=integer scalar=] type, and *f* in a floating point type.

<div class='example literals' heading="Type inference for literals">
  <xmp highlight=wgsl>
    // Explicitly-typed unsigned integer literal.
    var u32_1 = 1u; // variable holds a u32

    // Explicitly-typed signed integer literal.
    var i32_1 = 1i; // variable holds a i32

    // Explicitly-typed floating point literal.
    var f32_1 = 1f; // variable holds a f32

    // Explicitly-typed unsigned integer literal cannot be negated.
    var u32_neg = -1u; // invalid: unary minus does not support u32

    // When a concrete type is required, but no part of the statement or
    // expression forces a particular concrete type, an integer literal is
    // interpreted as an i32 value:
    //   Initializer for a let-declaration must be constructible (or pointer).
    //   The most preferred automatic conversion from AbstractInt to a constructible type
    //   is AbstractInt to i32, with conversion rank 2.  So '1' is inferred as i32.
    let some_i32 = 1; // like let some_i32: i32 = 1i;

    // Inferred from declaration type.
    var i32_from_type : i32 = 1; // variable holds i32.  AbstractInt to i32, conversion rank 2
    var u32_from_type : u32 = 1; // variable holds u32.  AbstractInt to u32, conversion rank 3

    // Unsuffixed integer literal can convert to floating point when needed:
    //   Automatically convert AbstractInt to f32, with conversion rank 5.
    var f32_promotion : f32 = 1; // variable holds f32

    // Invalid: no feasible conversion from floating point to integer
    var i32_demotion : i32 = 1.0; // Invalid

    // Inferred from expression.
    var u32_from_expr = 1 + u32_1; // variable holds u32
    var i32_from_expr = 1 + i32_1; // variable holds i32

    // Values must be representable.
    let u32_too_large   : u32 = 1234567890123456890; // invalid, overflow
    let i32_too_large   : i32 = 1234567890123456890; // invalid, overflow
    let u32_large : u32 = 2147483649; // valid
    let i32_large : i32 = 2147483649; // invalid, overflow
    let f32_out_of_range1 = 0x1p500; // invalid, out of range
    let f32_hex_lost_bits = 0x1.0000000001p0; // invalid, not exactly representable in f32

    // Minimum integer: unary negation over AbstractInt, then infer i32.
    // Most preferred conversion from AbstractInt to a constructible type (with lowest
    // conversion rank) is AbstractInt to i32.
    let i32_min = -2147483648;  // has type i32

    // Invalid.  Select AbstractInt to i32 as above, but the value is out of
    // range, producing shader-creation error.
    let i32_too_large_2 = 2147483648; // Invalid.

    // Subexpressions can resolve to AbstractInt and AbstractFloat.
    // The following examples are all valid and the value of the variable is 6u.
    var u32_expr1 = (1 + (1 + (1 + (1 + 1)))) + 1u;
    var u32_expr2 = 1u + (1 + (1 + (1 + (1 + 1))));
    var u32_expr3 = (1 + (1 + (1 + (1u + 1)))) + 1;
    var u32_expr4 = 1 + (1 + (1 + (1 + (1u + 1))));

    // Inference based on built-in function parameters.

    // Most-preferred candidate is clamp(i32,i32,i32)->i32
    let i32_clamp = clamp(1, -5, 5);
    // Most preferred candidate is clamp(u32,u32,u32).
    // Literals use automatic conversion AbstractInt to u32.
    let u32_clamp = clamp(5, 0, u32_from_expr);
    // Most preferred candidate is clamp(f32,f32,f32)->f32
    // literals use automatic conversion AbstractInt to f32.
    let f32_clamp = clamp(0, f32_1, 1);

    // The following examples all promote to f32 with an initial value of 10f.
    let f32_promotion1 = 1.0 + 2 + 3 + 4;
    let f32_promotion2 = 2 + 1.0 + 3 + 4;
    let f32_promotion3 = 1f + ((2 + 3) + 4);
    let f32_promotion4 = ((2 + (3 + 1f)) + 4);

    // Type rule violations.

    // Invalid, the initializer can only resolve to f32:
    // No feasible automatic conversion from AbstractFloat to u32.
    let mismatch : u32 = 1.0;

    // Invalid. There is no overload of clamp that allows mixed sign parameters.
    let ambiguous_clamp = clamp(1u, 0, 1i);

    // Inference completes at the statement level.

    // Initializer for a let-declaration must be constructible (or pointer).
    // The most preferred automatic conversion from AbstractInt to a constructible type
    // is AbstractInt to i32, with conversion rank 2.  So '1' is inferred as i32.
    let some_i32 = 1; // like let some_i32: i32 = 1i;

    let some_f32 : f32 = some_i32; // Type error: i32 cannot be assigned to f32

    // Another overflow case
    let overflow_u32 = (1 -2) + 1u; // invalid, -1 is out of range of u32

    // Ideal value out of range of 32-bits, but brought back into range
    let out_and_in_again = (0x1ffffffff / 8);

    // Similar, but invalid
    let out_of_range = (0x1ffffffff / 8u); // requires computation is done in 32-bits,
                                           // making 0x1ffffffff out of range.

  </xmp>
</div>

### Boolean Type ### {#bool-type}

The <dfn noexport>bool</dfn> type contains the values `true` and `false`.

<table class='data'>
  <caption>Boolean literal type rules</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr><td><td>`true`: bool<td>The true value.
  <tr><td><td>`false`: bool<td>The false value.
</table>

### Integer Types ### {#integer-types}

The <dfn noexport>u32</dfn> type is the set of 32-bit unsigned integers.

The <dfn noexport>i32</dfn> type is the set of 32-bit signed integers.
It uses a two's complementation representation, with the sign bit in the most significant bit position.

[[#arithmetic-expr|Expressions]] on [=type/concrete=] integer types that overflow produce a result that is modulo 2<sup><i>bitwidth</i></sup>

<table class='data'>
  <caption>Extreme values for integer types</caption>
  <thead>
    <tr><th>Type<th>Lowest value<th>Highest value
  </thead>
    <tr><td rowspan=2>i32<td>i32(-2147483648)<td>2147483647i
    <tr><td>i32(-0x80000000)<td>0x7fffffffi
    <tr><td rowspan=2>u32<td>0u<td>4294967295u
    <tr><td>0x0u<td>0xffffffffu
</table>

Note: [=AbstractInt=] is also an integer type.

### Floating Point Types ### {#floating-point-types}

The <dfn noexport>f32</dfn> type is the set of 32-bit floating point values of the
[[!IEEE-754|IEEE-754]] binary32 (single precision) format.
See [[#floating-point-evaluation]] for details.

The <dfn noexport>f16</dfn> type is the set of 16-bit floating point values of the
[[!IEEE-754|IEEE-754]] binary16 (half precision) format. It is a [=shader-creation error=]
if the [=f16=] type is used unless the program contains the `enable f16;` directive to enable
the [=extension/f16|f16 extension=]. See [[#floating-point-evaluation]] for details.

The following table lists certain extreme values for floating point types.
Each has a corresponding negative value.
<table class='data'>
  <caption>Extreme values for floating point types</caption>
  <thead>
    <tr><th>Type<th>Smallest positive denormal<th>Smallest positive normal<th>Largest positive finite<th>Largest finite power of 2
  </thead>
    <tr><td rowspan=2>f32<td>1.40129846432481707092e-45f<td>1.17549435082228750797e-38f<td>3.40282346638528859812e+38f<td rowspan=2>0x1p+127f
    <tr><td>0x1p-149f<td>0x1p-126f<td>0x1.fffffep+127f
    <tr><td rowspan=2>f16<td>5.9604644775390625e-8h<td>0.00006103515625h<td>65504.0h<td rowspan=2>0x1p+15h
    <tr><td>0x1p-24h<td>0x1p-14h<td>0x1.ffcp+15h
</table>

Note: [=AbstractFloat=] is also a floating point type.

### Scalar Types ### {#scalar-types}

The <dfn noexport>scalar</dfn> types are [=bool=], [=AbstractInt=],
[=AbstractFloat=], [=i32=], [=u32=], [=f32=], and [=f16=].

The <dfn noexport>numeric scalar</dfn> types are [=AbstractInt=],
[=AbstractFloat=], [=i32=], [=u32=], [=f32=], and [=f16=].

The <dfn noexport>integer scalar</dfn> types are [=AbstractInt=], [=i32=], and
[=u32=].

### Vector Types ### {#vector-types}

A <dfn noexport>vector</dfn> is a grouped sequence of 2, 3, or 4 [=scalar=]
components.

<table class='data'>
  <thead>
    <tr><th>Type<th>Description
  </thead>
  <tr><td>vec*N*<*T*><td>Vector of *N* components of type *T*.
                          *N* must be in {2, 3, 4} and *T* [=shader-creation
                          error|must=] be one of the [=scalar=] types.
                          We say *T* is the <dfn noexport>component type</dfn> of the vector.
</table>

A vector is a <dfn noexport>numeric vector</dfn> if its component type is a [=numeric scalar=].

Key use cases of a vector include:

* to express both a direction and a magnitude.
* to express a position in space.
* to express a color in some color space.
    For example, the components could be intensities of red, green, and blue,
    while the fourth component could be an alpha (opacity) value.

Many operations on vectors (and [=matrix|matrices=]) act <dfn
noexport>component-wise</dfn>, i.e. the result is formed by operating on
each scalar component independently.

<div class='example wgsl type-scope' heading='Vector'>
  <xmp highlight=wgsl>
    vec2<f32>  // is a vector of two f32s.
  </xmp>
</div>

<div class='example wgsl function-scope component-wise addition' heading='Component-wise addition'>
  <xmp highlight=wgsl>
    let x : vec3<f32> = a + b; // a and b are vec3<f32>
    // x[0] = a[0] + b[0]
    // x[1] = a[1] + b[1]
    // x[2] = a[2] + b[2]
  </xmp>
</div>

WGSL also [=predeclared|predeclares=] the following [=type aliases=]:

<table class='data'>
  <thead>
    <tr>
        <th>Predeclared alias
        <th>Original type
        <th>Restrictions
  </thead>
  <tr>
      <td><dfn noexport>vec2i</dfn>
      <td>vec2&lt;i32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec3i</dfn>
      <td>vec3&lt;i32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec4i</dfn>
      <td>vec4&lt;i32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec2u</dfn>
      <td>vec2&lt;u32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec3u</dfn>
      <td>vec3&lt;u32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec4u</dfn>
      <td>vec4&lt;u32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec2f</dfn>
      <td>vec2&lt;f32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec3f</dfn>
      <td>vec3&lt;f32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec4f</dfn>
      <td>vec4&lt;f32&gt;
      <td>
  <tr>
      <td><dfn noexport>vec2h</dfn>
      <td>vec2&lt;f16&gt;
      <td rowspan=3>Requires the [=extension/f16|f16 extension=].
  <tr>
      <td><dfn noexport>vec3h</dfn>
      <td>vec3&lt;f16&gt;
  <tr>
      <td><dfn noexport>vec4h</dfn>
      <td>vec4&lt;f16&gt;
</table>

### Matrix Types ### {#matrix-types}

A <dfn noexport>matrix</dfn> is a grouped sequence of 2, 3, or 4 floating point vectors.

<table class='data'>
  <thead>
    <tr><th>Type<th>Description
  </thead>
  <tr algorithm="matrix type">
    <td>mat|C|x|R|&lt;|T|&gt;
    <td>Matrix of |C| columns and |R| rows of type |T|, where |C| and |R| are both in {2, 3, 4}, and |T| must be [=f32=], [=f16=], or [=AbstractFloat=].
        Equivalently, it can be viewed as |C| column vectors of type vec|R|&lt;*T*&gt;.
</table>

The key use case for a matrix is to embody a linear transformation.
In this interpretation, the vectors of a matrix are treated as column vectors.

The product operator (`*`) is used to either:

* scale the transformation by a scalar magnitude.
* apply the transformation to a vector.
* combine the transformation with another matrix.

See [[#arithmetic-expr]].

<div class='example wgsl type-scope' heading='Matrix'>
  <xmp highlight=wgsl>
    mat2x3<f32>  // This is a 2 column, 3 row matrix of 32-bit floats.
                 // Equivalently, it is 2 column vectors of type vec3<f32>.
  </xmp>
</div>

WGSL also [=predeclared|predeclares=] the following [=type aliases=]:

<table class='data'>
  <thead>
    <tr>
        <th>Predeclared alias
        <th>Original type
        <th>Restrictions
  </thead>
  <tr> <td><dfn noexport>mat2x2f</dfn> <td>mat2x2&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat2x3f</dfn> <td>mat2x3&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat2x4f</dfn> <td>mat2x4&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat3x2f</dfn> <td>mat3x2&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat3x3f</dfn> <td>mat3x3&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat3x4f</dfn> <td>mat3x4&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat4x2f</dfn> <td>mat4x2&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat4x3f</dfn> <td>mat4x3&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat4x4f</dfn> <td>mat4x4&lt;f32&gt; <td>
  <tr> <td><dfn noexport>mat2x2h</dfn> <td>mat2x2&lt;f16&gt; <td rowspan=9>Requires the [=extension/f16|f16 extension=].
  <tr> <td><dfn noexport>mat2x3h</dfn> <td>mat2x3&lt;f16&gt;
  <tr> <td><dfn noexport>mat2x4h</dfn> <td>mat2x4&lt;f16&gt;
  <tr> <td><dfn noexport>mat3x2h</dfn> <td>mat3x2&lt;f16&gt;
  <tr> <td><dfn noexport>mat3x3h</dfn> <td>mat3x3&lt;f16&gt;
  <tr> <td><dfn noexport>mat3x4h</dfn> <td>mat3x4&lt;f16&gt;
  <tr> <td><dfn noexport>mat4x2h</dfn> <td>mat4x2&lt;f16&gt;
  <tr> <td><dfn noexport>mat4x3h</dfn> <td>mat4x3&lt;f16&gt;
  <tr> <td><dfn noexport>mat4x4h</dfn> <td>mat4x4&lt;f16&gt;
</table>

### Atomic Types ### {#atomic-types}

An <dfn noexport>atomic type</dfn> encapsulates a [=type/concrete=] [=integer scalar=] type such that:
* atomic objects provide [[#memory-model|certain guarantees]] to concurrent observers, and
* the only valid operations on atomic objects are the [[#atomic-builtin-functions|atomic builtin functions]].

<table class='data'>
  <thead>
    <tr><th>Type<th>Description
  </thead>
  <tr algorithm="atomic type"><td>atomic&lt;|T|&gt;
    <td>Atomic of type |T|. |T| [=shader-creation error|must=] be either [=u32=] or [=i32=].
</table>

An expression [=shader-creation error|must not=] evaluate to an atomic type.

Atomic types may only be instantiated by variables in the [=address spaces/workgroup=]
address space or by [=storage buffer=] variables with a [=access/read_write=] access mode.
The [=memory scope=] of operations on the type is determined by the [=address space=]
it is instantiated in.
Atomic types in the [=address spaces/workgroup=] address space have a
[[#scoped-operations|memory scope]] of `Workgroup`, while those in the
[=address spaces/storage=] address space have a memory scope of `QueueFamily`.

An <dfn noexport>atomic modification</dfn> is any
[[#memory-operation|operation]] on an atomic object which sets the content of
the object.
The operation counts as a modification even if the new value is the same as the
object's existing value.

In WGSL, atomic modifications are mutually ordered, for each object.
That is, during execution of a shader stage, for each atomic object *A*, all
agents observe the same order of modification operations applied to *A*.
The ordering for distinct atomic objects may not be related in any way; no
causality is implied.
Note that variables in [=address spaces/workgroup=] space are shared within a
[=compute shader stage/workgroup=], but are not shared between different
workgroups.


### Array Types ### {#array-types}

An <dfn noexport>array</dfn> is an indexable sequence of element values.

<table class='data'>
  <thead>
    <tr><th>Type<th>Description
  </thead>
  <tr><td algorithm="fixed-size array type">array&lt;|E|,|N|&gt;
      <td>A <dfn>fixed-size array</dfn> with |N| elements of type |E|.<br>
          |N| is called the <dfn noexport>element count</dfn> of the array.
  <tr><td algorithm="runtime-sized array type">array&lt;|E|&gt;
      <td>A <dfn noexport>runtime-sized</dfn> array of elements of type |E|.
          These may only appear in specific contexts.<br>
</table>

The first element in an array is at index 0, and each successive element is at the next integer index.
See [[#array-access-expr]].

An expression [=shader-creation error|must not=] evaluate to a runtime-sized array type.

The element count expression |N| of a fixed-size array is subject to the following constraints:
* It [=shader-creation error|must=] be an [=override-expression=].
* It [=shader-creation error|must=] evaluate to a [=type/concrete=] [=integer scalar=].
* If |N| is not greater than zero:
    * It is a [=shader-creation error=] if |N| is a [=const-expression=].
    * Otherwise, it is a [=pipeline-creation error=].

Note:  The element count value is fully determined at [=pipeline creation=]
time if |N| depends on any [=override-declarations=], and [=shader module creation=]
otherwise.

Note:  To qualify for type-equivalency, any override expression that is not a const expression must be an **identifier**.
See <a href="#example-workgroup-variables-sized-by-override">Workgroup variables sized by overridable constants</a>

The number of elements in a runtime-sized array
is determined by the size of buffer binding associated with the corresponding [=storage buffer=] variable.
See [[#buffer-binding-determines-runtime-sized-array-element-count]].

An array element type [=shader-creation error|must=] be one of:
* a [=scalar=] type
* a [=vector=] type
* a [=matrix=] type
* an [=atomic type|atomic=] type
* an [=array=] type having a [=creation-fixed footprint=]
* a [=structure=] type having a [=creation-fixed footprint=].

Note: The element type must be a [=plain type=].

Two array types are the same if and only if all of the following are true:
* They have the same element type.
* Their element count specifications match, i.e. one of the following is true:
    * They are both runtime-sized.
    * They are both fixed-sized with [=creation-fixed footprint=], and
        equal-valued element counts, even if one is signed and the other is unsigned.
        (Signed and unsigned values are comparable in this case because element counts
        are always positive.)
    * They are both fixed-sized with element counts specified as identifiers [=resolves|resolving=]
        to the same declaration of a [=pipeline-overridable=] constant.

<div class='example wgsl fixed-size array types' heading='Example fixed-size array types, non-overridable element count'>
  <xmp highlight=wgsl>
    // array<f32,8> and array<i32,8> are different types:
    // different element types
    var<private> a: array<f32,8>;
    var<private> b: array<i32,8>;
    var<private> c: array<i32,8u>;  // array<i32,8> and array<i32,8u> are the same type

    const width = 8;
    const height = 8;

    // array<i32,8>, array<i32,8u>, and array<i32,width> are the same type.
    // Their element counts evaluate to 8.
    var<private> d: array<i32,width>;

    // array<i32,height> and array<i32,width> are the same type.
    var<private> e: array<i32,width>;
    var<private> f: array<i32,height>;
  </xmp>
</div>

Note: The only valid use of an array type sized by an overridable constant is
as a [=memory view=] in the [=address spaces/workgroup=] address space.
This includes the [=store type=] of a workgroup variable.
See [[#var-and-value]].

<div class='example wgsl global-scope'
   heading="Workgroup variables sized by overridable constants"
   id="example-workgroup-variables-sized-by-override">
  <xmp highlight=wgsl>
    override blockSize = 16;

    var<workgroup> odds: array<i32,blockSize>;
    var<workgroup> evens: array<i32,blockSize>; // Same type

    // None of the following have the same type as 'odds' and 'evens'.

    // Different type: Not the identifier 'blockSize'
    var<workgroup> evens_0: array<i32,16>;
    // Different type: Uses arithmetic to express the element count.
    var<workgroup> evens_1: array<i32,(blockSize * 2 / 2)>;
    // Different type: Uses parentheses, not just an identifier.
    var<workgroup> evens_2: array<i32,(blockSize)>;

    // An invalid example, because the overridable element count may only occur
    // at the outer level.
    // var<workgroup> both: array<array<i32,blockSize>,2>;

    // An invalid example, because the overridable element count is only
    // valid for workgroup variables.
    // var<private> bad_address_space: array<i32,blockSize>;
  </xmp>
</div>

### Structure Types ### {#struct-types}

A <dfn noexport>structure</dfn> is a named grouping of named <dfn noexport>member</dfn> values.

<table class='data'>
  <thead>
    <tr><th>Type<th>Description
  </thead>
  <tr algorithm="structure type">
      <td>`struct`&nbsp;|AStructName|&nbsp;{<br>
           &nbsp;&nbsp;<var ignore>M<sub>1</sub></var> : <var ignore>T<sub>1</sub></var>,<br>
           &nbsp;&nbsp;...<br>
           &nbsp;&nbsp;<var ignore>M<sub>N</sub></var> : <var ignore>T<sub>N</sub></var>,<br>
           }
      <td> A declaration of a structure type named by the [=identifier=] |AStructName|
           and having |N| members,
           where member <var ignore>i</var>
           is named by the identifier <var ignore>M<sub>|i|</sub></var>
           and is of the type <var ignore>T<sub>|i|</sub></var>.

           |N| [=shader-creation error|must=] be at least 1.

           Two members of the same structure type [=shader-creation error|must not=] have the same name.
</table>

Structure types are declared at [=module scope=].
Elsewhere in the program source, a structure type is denoted by its identifier name.
See [[#declaration-and-scope]].

Two structure types are the same if and only if they have the same name.

A structure member type [=shader-creation error|must=] be one of:
* a [=scalar=] type
* a [=vector=] type
* a [=matrix=] type
* an [=atomic type|atomic=] type
* a [=fixed-size array=] type with [=creation-fixed footprint=]
* a [=runtime-sized=] array type, but only if it is the last member of the structure
* a [=structure=] type that has a [=creation-fixed footprint=]

Note: All user-declared structure types are [=type/concrete=].

Note: Each member type must be a [=plain type=].

Some consequences of the restrictions structure member and array element types are:
* A pointer, texture, or sampler [=shader-creation error|must not=] appear in any level of nesting within an array or structure.
* When a [=runtime-sized=] array is part of a larger type, it may only appear
    as the last element of a structure, which itself cannot be part of an enclosing array or structure.

<div class='example wgsl global-scope' heading="Structure">
  <xmp highlight=wgsl>
    // A structure with three members.
    struct Data {
      a: i32,
      b: vec2<f32>,
      c: array<i32,10>, // last comma is optional
    }

    // Declare a variable storing a value of type Data.
    var<private> some_data: Data;
  </xmp>
</div>

<pre class=include>
path: syntax/struct_decl.syntax.bs.include
</pre>
<pre class=include>
path: syntax/struct_body_decl.syntax.bs.include
</pre>
<pre class=include>
path: syntax/struct_member.syntax.bs.include
</pre>

The following attributes can be applied to structure members:
 * [=attribute/align=]
 * [=attribute/builtin=]
 * [=attribute/location=]
 * [=attribute/blend_src=]
 * [=attribute/interpolate=]
 * [=attribute/invariant=]
 * [=attribute/size=]

Attributes [=attribute/builtin=], [=attribute/location=], [=attribute/blend_src=],
[=attribute/interpolate=], and [=attribute/invariant=] are [=IO attributes=].
An [=IO attribute=] on a member of a structure *S* has effect only when
*S* is used as the type of a [=formal parameter=] or [=return type=] of an [=entry point=].
See [[#stage-inputs-outputs]].

Attributes [=attribute/align=] and [=attribute/size=] are [=layout attributes=],
and may be required if the structure type is used to
define a [=uniform buffer=] or a [=storage buffer=].
See [[#memory-layouts]].

<div class='example wgsl global-scope' heading='Structure declaration'>
  <xmp highlight=wgsl>
    struct my_struct {
      a: f32,
      b: vec4<f32>
    }
  </xmp>
</div>

<div class='example wgsl global-scope' heading='Structure used to declare a buffer'>
  <xmp highlight=wgsl>
    // Runtime Array
    alias RTArr = array<vec4<f32>>;
    struct S {
      a: f32,
      b: f32,
      data: RTArr
    }
    @group(0) @binding(0) var<storage> buffer: S;
  </xmp>
</div>

### Composite Types ### {#composite-types}

A type is <dfn noexport>composite</dfn> if it has internal structure
expressed as a composition of other types.
The internal parts do not overlap, and are called <dfn noexport>components</dfn>.
A composite value may be decomposed into its components. See [[#composite-value-decomposition-expr]].

The composite types are:

* [=vector=] type
* [=matrix=] type
* [=array=] type
* [=structure=] type

For a composite type |T|, the <dfn>nesting depth</dfn> of |T|, written *NestDepth*(|T|) is:
* 1 for a vector type
* 2 for a matrix type
* 1 + *NestDepth*(|E|) for an array type with element type |E|
* 1 + max(*NestDepth*(*M*<sub>1</sub>),..., *NestDepth*(*M*<sub>N</sub>))
    if |T| is a structure type with member types *M*<sub>1</sub>,...,*M*<sub>N</sub>


### Constructible Types ### {#constructible-types}

Many kinds of values can be created, loaded, stored, passed into functions,
and returned from functions.
We call these [=constructible=].

A type is <dfn>constructible</dfn> if it is one of:

* a [=scalar=] type
* a [=vector=] type
* a [=matrix=] type
* a [=fixed-size array=] type, if it has [=creation-fixed footprint=] and its element type is constructible.
* a [=structure=] type, if all its members are constructible.

Note: All constructible types have a [=creation-fixed footprint=].

Note: Atomic types and runtime-sized array types are not constructible.
Composite types containing atomics and runtime-sized arrays are not constructible.

### Fixed-Footprint Types ### {#fixed-footprint-types}

The <dfn noexport>memory footprint</dfn> of a variable is the number of [=memory locations=]
used to store the contents of the variable.
The memory footprint of a variable depends on its [=store type=] and becomes finalized at some point
in the [[#shader-lifecycle|shader lifecycle]].
Most variables are sized very early, at [=Shader module creation|shader creation=] time.
Some variables may be sized later, at [=pipeline creation=] time,
and others as late as the [=shader execution start|start of shader execution=].

A type has a <dfn>creation-fixed footprint</dfn> if its [=feasible automatic
conversion|concretization=] has a size that is fully determined at [=shader
module creation|shader creation=] time.

A type has a <dfn>fixed footprint</dfn> if its size is fully determined
at [=pipeline creation=] time.

Note: All [=type/concrete=] creation-fixed footprint and fixed footprint types are [=storable=].

Note: Pipeline creation depends on shader creation, so a type with [=creation-fixed footprint=] also has [=fixed footprint=].

The types with [=creation-fixed footprint=] are:
* a [=scalar=] type
* a [=vector=] type
* a [=matrix=] type
* an [=atomic type|atomic=] type
* a [=fixed-size array=] type, when:
     * its [=element count=] is a [=const-expression=].
* a [=structure=] type, if all its members have [=creation-fixed footprint=].

Note: A [=constructible=] type has a [=creation-fixed footprint=].

The [=plain types=] with [=fixed footprint=] are any of:
* a type with [=creation-fixed footprint=]
* a [=fixed-size array=] type (without further constraining its [=element count=])

Note: The only valid use of a fixed-size array with an element count that is an
[=override-expression=] that is not a [=const-expression=] is as a
[=memory view=] in the [=address spaces/workgroup=] address space.
This includes the [=store type=] of a workgroup variable.

Note: A fixed-footprint type may contain an [=atomic type|atomic=] type, either directly or
indirectly, while a [=constructible=] type cannot.

Note: Fixed-footprint types exclude [=runtime-sized=] arrays, and any structure
that contains a [=runtime-sized=] array.

## Enumeration Types ## {#enumeration-types}

An <dfn noexport>enumeration</dfn> type is a limited set of named values.
An enumeration is used to distinguish among the set of possibilities for a specific concept, such as the set of valid [=texel formats=].

An <dfn noexport>enumerant</dfn> is one of the named values in an [=enumeration=].
Each [=enumerant=] is distinct from all other enumerants, and distinct from all other kinds of values.

There is no mechanism for declaring new enumerants or new enumeration types in WGSL source.

Note: Enumerants are used as [=template parameters=].

<div class=note>
<span class=marker>Note:</span> There is no way to copy or to create an alternative name for an enumerant:
* A [[#var-and-value|variable or value]] declaration cannot have an enumeration as its [=store type=] or its [=effective-value-type=].
* A function formal parameter cannot be an enumeration type, in part because enumerations are not [=constructible=].

</div>

### Predeclared enumerants ### {#predeclared-enumerants}

The following table lists the [=enumeration=] types in WGSL, and their [=predeclared=] [=enumerants=].
The enumeration types exist, but cannot be spelled in WGSL source.

<table class=data>
<caption>
  Predeclared enumerants
</caption>
<thead>
  <tr><th>Enumeration<br>(Cannot be spelled in WGSL)<th>Predeclared enumerant
</thead>
  <tr><td rowspan=3>[=access mode=]<td>[=access/read=]
  <tr><td>[=access/write=]
  <tr><td>[=access/read_write=]
  <tr><td rowspan=5>[=address space=]

      Note: The `handle` address space is never written in a WGSL source.
      <td>[=address spaces/function=]
  <tr><td>[=address spaces/private=]
  <tr><td>[=address spaces/workgroup=]
  <tr><td>[=address spaces/uniform=]
  <tr><td>[=address spaces/storage=]
  <tr><td rowspan=17>[=texel format=]
      <td>[=texel format/rgba8unorm=]
  <tr><td>[=texel format/rgba8snorm=]
  <tr><td>[=texel format/rgba8uint=]
  <tr><td>[=texel format/rgba8sint=]
  <tr><td>[=texel format/rgba16uint=]
  <tr><td>[=texel format/rgba16sint=]
  <tr><td>[=texel format/rgba16float=]
  <tr><td>[=texel format/r32uint=]
  <tr><td>[=texel format/r32sint=]
  <tr><td>[=texel format/r32float=]
  <tr><td>[=texel format/rg32uint=]
  <tr><td>[=texel format/rg32sint=]
  <tr><td>[=texel format/rg32float=]
  <tr><td>[=texel format/rgba32uint=]
  <tr><td>[=texel format/rgba32sint=]
  <tr><td>[=texel format/rgba32float=]
  <tr><td>[=texel format/bgra8unorm=]
</table>

## Memory Views ## {#memory-views}

In addition to calculating with [=plain types|plain=] values, a WGSL program will
also often read values from [[#memory|memory]] or write values to memory, via [=memory access=] operations.
Each memory access is performed via a [=memory view=].

A <dfn noexport>memory view</dfn> comprises:
* a set of [=memory locations=] in a particular [=address space=],
* a [[#memory-model-reference|memory model reference]],
* an interpretation of the contents of those locations as a WGSL [=type=], known as the <dfn noexport>store type</dfn>, and
* an [=access mode=].

The access mode of a memory view [=shader-creation error|must=] be supported by the address space. See [[#var-and-value]].

### Storable Types ### {#storable-types}

The value contained in a [=variable=] [=shader-creation error|must=] be of a [=storable=] type.
A storable type may have an explicit representation defined by WGSL,
as described in [[#internal-value-layout]],
or it may be opaque, such as for [=texture resource|textures=] and [=sampler resource|samplers=].

A type is <dfn noexport>storable</dfn> if it is both [=type/concrete=] and one of:

* a [=scalar=] type
* a [=vector=] type
* a [=matrix=] type
* an [=atomic type|atomic=] type
* an [=array=] type
* a [=structure=] type
* a [=texture=] type
* a [=sampler=] type

Note: That is, the storable types are the [=type/concrete=] [=plain types=], texture types, and sampler types.

### Host-shareable Types ### {#host-shareable-types}

Host-shareable types are used to describe the contents of buffers which are shared between
the host and the GPU, or copied between host and GPU without format translation.
When used for this purpose, the type may additionally have [=layout
attributes=] applied as described in [[#memory-layouts]].
As described in [[#var-decls]], the [=store type=] of [=uniform buffer=] and [=storage buffer=]
variables [=shader-creation error|must=] be host-shareable.

A type is <dfn noexport>host-shareable</dfn> if it is both [=type/concrete=] and one of:

* a [=numeric scalar=] type
* a [=numeric vector=] type
* a [=matrix=] type
* an [=atomic type|atomic=] type
* a [=fixed-size array=] type, if it has [=creation-fixed footprint=] and its element type is host-shareable
* a [=runtime-sized=] array type, if its element type is host-shareable
* a [=structure=] type, if all its members are host-shareable

Note: Restrictions on the types of inter-stage inputs and outputs]] are
described in [[#stage-inputs-outputs]] and subsequent sections.
Those types are also sized, but the counting is differs.

Note: [[#texture-sampler-types|Textures and samplers]] can also be shared
between the host and the GPU, but their contents are opaque.
The host-shareable types in this section are specifically for use in [=storage
buffer|storage=] and [=uniform buffer|uniform=] buffers.

### Reference and Pointer Types ### {#ref-ptr-types}

WGSL has two kinds of types for representing [=memory views=]:
[=reference types=] and [=pointer types=].

<table class='data'>
  <thead>
    <tr><th>Constraint<th>Type<th>Description
  </thead>
  <tr algorithm="memory reference type">
    <td style="width:25%">|AS| is an [=address space=],<br>|T| is a [=storable=] type,<br>|AM| is an [=access mode=]
    <td>ref&lt;|AS|,|T|,|AM|&gt;
    <td>The <dfn noexport>reference type</dfn>
        identified with the set of [=memory views=] for memory locations in |AS| holding values of type |T|,
        supporting memory accesses described by mode |AM|.

        Here, |T| is the [=store type=].

        Reference types are not written in WGSL source;
        instead they are used to analyze a WGSL module.
  <tr algorithm="pointer type">
    <td>|AS| is an [=address space=],<br>|T| is a [=storable=] type,<br>|AM| is an [=access mode=]
    <td>ptr&lt;|AS|,|T|,|AM|&gt;
    <td>The <dfn noexport>pointer type</dfn>
        identified with the set of [=memory views=] for memory locations in |AS| holding values of type |T|,
        supporting memory accesses described by mode |AM|.

        Here, |T| is the [=store type=].

        Pointer types may appear in WGSL source.
</table>

Two pointer types are the same if and only if they have the same address space, store type, and access mode.

When *analyzing* a WGSL module, reference and pointer types are fully parameterized by
an address space, a storable type, and an access mode.
In code examples in this specification, the comments show this fully parameterized form.

However, in WGSL *source* text:
* Reference types [=shader-creation error|must not=] appear.
* Pointer types may appear.
    * A pointer type is spelled with parameterization by:
        * [=address space=],
        * [=store type=], and
        * sometimes by [=access mode=], as specified in [[#address-space]].
    * If a pointer type appears in the program source,
        it [=shader-creation error|must=] also be valid to [=variable declaration|declare a variable=],
        somewhere in the program,
        with the pointer type's [=address space=], [=store type=], and [=access mode=].

        Note: This restriction forbids the declaration of certain [=type aliases=]
        and function [=formal parameters=] that can never be used at runtime.
        Without the restriction, it would be valid to declare an alias to a pointer type,
        but never be able to create a pointer value of that type.
        Similarly, it would be valid to declare a function with a pointer formal parameter,
        but never be able to call that function.

<div class='example wgsl' heading='Pointer type'>
  <xmp highlight=wgsl>
    fn my_function(
      /* 'ptr<function,i32,read_write>' is the type of a pointer value that references
         memory for keeping an 'i32' value, using memory locations in the 'function'
         address space.  Here 'i32' is the store type.
         The implied access mode is 'read_write'.
         See "Address Space" section for defaults. */
      ptr_int: ptr<function,i32>,

      // 'ptr<private,array<f32,50>,read_write>' is the type of a pointer value that
      // refers to memory for keeping an array of 50 elements of type 'f32', using
      // memory locations in the 'private' address space.
      // Here the store type is 'array<f32,50>'.
      // The implied access mode is 'read_write'.
      // See the "Address space section for defaults.
      ptr_array: ptr<private, array<f32, 50>>
    ) { }
  </xmp>
</div>

Reference types and pointer types are both sets of memory views:
a particular memory view is associated with a unique reference value and also a unique pointer value:

<blockquote algorithm="pointer reference correspondence">
Each pointer value |p| of type ptr&lt;|AS|,|T|,|AM|&gt; corresponds to a unique reference value |r| of type ref&lt;|AS|,|T|,|AM|&gt;,
and vice versa,
where |p| and |r| describe the same memory view.
</blockquote>

### Valid and Invalid Memory References ### {#valid-invalid-memory-references}

A [=reference type|reference=] value is either [=valid reference|valid=] or [=invalid memory reference|invalid=].

References are formed as described in detail in [[#forming-references-and-pointers]].
Generally, a <dfn noexport>valid reference</dfn> is formed by:
* naming a variable, or
* applying the [=indirection=] (unary `*`) operation to a [=valid pointer=], or
* a [=named component expression=] where the [=decomposition/base=] is a valid [=memory view=], or
* an [=indexing expression=] where the [=decomposition/base=] is a valid [=memory view=], and using an [=in-bounds index=].

Generally, an <dfn noexport>invalid memory reference</dfn> is formed by:
* applying the indirection operator to an [=invalid pointer=], or
* a [=named component expression=] where the [=decomposition/base=] is an invalid memory reference, or
* an [=indexing expression=] where the base is a [=memory view=], and either:
     * the [=decomposition/base=] is an invalid memory reference, or
     * the index is [=out-of-bounds index|out-of-bounds=].

A <dfn noexport>valid pointer</dfn> is a pointer that corresponds to a [=valid reference=].
An <dfn noexport>invalid pointer</dfn> is a pointer that corresponds to an [=invalid memory reference=].

### Originating Variable ### {#originating-variable-section}

<div algorithm="defining orginating variable">
The <dfn noexport>originating variable</dfn> for a reference value |R| is defined as follows:
* It is the variable, when |R| is a variable.
* It is the originating variable of the pointer value |P|, when |R| is the application of the indirection operator (unary *) on |P|.
* It is the originating variable of the [=decomposition/base=], when |R| is a [=named component expression=] or an [=indexing expression=].

</div>

The [=originating variable=] of a pointer value is defined as the originating variable of the corresponding reference value.

Note: The originating variable is a dynamic concept.
The originating variable for a formal parameter of a function depends on the
[=call site|call sites=] for the function.
Different call sites may supply pointers into different originating variables.

A [=valid reference=] always corresponds to a non-empty memory view for some or all of the memory locations for some variable.

<div class=note>
<span class=marker>Note:</span> A reference can correspond to memory locations inside a variable, and still be invalid.
This can occur when an index is too large for the type being indexed, but the referenced locations
would be inside a subsequent sibling data member.

In the following example, the reference `the_particle.position[i]` is valid if and only if `i` is 0 or 1.
When `i` is 2, the reference will be an [=invalid memory reference=], but would otherwise correspond
the memory locations for `the_particle.color_index`.
<div class='example wgsl' heading='Invalid memory reference still inside a variable'>
<span id="example-invalid-ref"></span>
  <xmp highlight=wgsl>
    struct Particle {
       position: vec2f,
       velocity: vec2f,
       color_index: i32,
    }

    @group(0) @binding(0)
    var<storage,read_write> the_particle: Particle;

    fn particle_velocity_component(p: Particle, i: i32) -> f32 {
      return the_particle.velocity[i]; // A valid reference when i is 0 or 1.
    }
  </xmp>
</div>
</div>

### Out-of-Bounds Access ### {#out-of-bounds-access-sec}

An operation that [=memory access|accesses=] an
[=invalid memory reference=] is an <dfn noexport>out-of-bounds access</dfn>.

An out-of-bounds access is a program defect, because if it *were* performed as written, it would typically:
* read or write [=memory locations=] outside of a variable, or
* interpret the contents of those locations as the wrong [=store type=], or
* cause an unintended data race.

For this reason, an implementation [=behavioral requirement|will not=] perform the access as written.
Executing an [=out-of-bounds access=] generates a [=dynamic error=].

Note: An example of interpreting the store type incorrectly occurs in
<a href="#example-invalid-ref"> the example from the previous section</a>.
When `i` is 2, the expression `the_particle.velocity[i]` has
type `ref<storage,f32,read_write>`, meaning it is a memory view with [=f32=] as
its [=store type=].
However, the memory locations are allocated to for the
`color_index` member, so the stored value is actually of type [=i32=].

<div class=note>
<span class=marker>Note:</span>An out-of-bounds access causes a dynamic error,
which allows for many possible outcomes.

Those outcomes include, but are not limited to, the following:

: <dfn noexport>Trap</dfn>
:: The shader invocation immediately terminates, and [=shader stage outputs=] are set to zero values.
: <dfn noexport>Invalid Load</dfn>
:: [=Load Rule|Loads=] from an invalid reference may return one of:
    * when the [=originating variable=] is a [=uniform buffer=] or a [=storage buffer=],
        the value from any [=memory locations|memory location(s)=]
        of the WebGPU {{GPUBuffer}} bound to the originating variable
    * when the originating variable is not a [=uniform buffer=] or [=storage buffer=],
        a value from any [=memory locations|memory location(s)=] in the originating variable
    * the [=zero value=] for store type of the reference
    * if the loaded value is a vector, the value (0, 0, 0, x), where x is:
        * 0, 1, or the maximum positive value for integer components
        * 0.0 or 1.0 for floating-point components
: <dfn noexport>Invalid Store</dfn>
:: [=statement/assignment|Stores=] to an invalid reference may do one of:
    * when the [=originating variable=] is a [=storage buffer=],
        store the value to any [=memory locations|memory location(s)=] of the
        WebGPU {{GPUBuffer}} bound to the [=originating variable=]
    * when the [=originating variable=] is not a [=storage buffer=],
        store the value to any [=memory locations|memory locations(s)=] in the
        originating variable
    * not be executed.

A data race may occur if an invalid load or store is redirected to access different
locations inside a variable in a shared address space.
For example, the accesses of several concurrently executing invocations may be redirected
to the first element in an array.
If at least one access is a write, and they are not otherwise synchronized,
then the result is a data race, and hence a dynamic error.

An out-of-bounds access invalidates the assumptions of [[#uniformity|uniformity analysis]].
For example, if an invocation terminates early due to an out-of-bounds access, then it
can no longer particpate in collective operations.
In particular, a call to [[#sync-builtin-functions|workgroupBarrier]] may hang the shader,
and derivatives may yield invalid results.
</div>

### Use Cases for References and Pointers ### {#ref-ptr-use-cases}

References and pointers are distinguished by how they are used:

* The type of a [=variable=] is a reference type.
* The [=address-of=] operation (unary `&`) converts a reference value to its corresponding pointer value.
* The [=indirection=] operation (unary `*`) converts a pointer value to its corresponding reference value.
* A [=let-declaration=] can be of pointer type, but not of reference type.
* A [=formal parameter=] can be of pointer type, but not of reference type.
* A [=simple assignment=] statement performs a [=write access=] to update the contents of memory via a reference, where:
    * The [=left-hand side=] of the assignment statement [=shader-creation error|must=] be of reference type, with access mode [=access/write=] or [=access/read_write=].
    * The [=right-hand side=] of the assignment statement [=shader-creation error|must=] evaluate to the store type of the left-hand side.
* The <dfn noexport>Load Rule</dfn>: Inside a function, a reference is automatically dereferenced (read from) to satisfy type rules:
    * In a function, when a reference expression |r| with store type |T| is used in a statement or an expression, where
    * |r| has an access mode of [=access/read=] or [=access/read_write=], and
    * The only potentially matching type rules require |r| to have a value of type |T|, then
    * That type rule requirement is considered to have been met, and
    * The result of evaluating |r| in that context is the value (of type |T|) stored in the memory locations
        referenced by |r| at the time of evaluation.
        That is, a [=read access=] is performed to produce the result value.

Defining references in this way enables simple idiomatic use of variables:

<div class='example wgsl' heading='Reference types enable simple use of variables'>
  <xmp highlight=wgsl>
    @compute @workgroup_size(1)
    fn main() {
      // 'i' has reference type ref<function,i32,read_write>
      // The memory locations for 'i' store the i32 value 0.
      var i: i32 = 0;

      // 'i + 1' can only match a type rule where the 'i' subexpression is of type i32.
      // So the expression 'i + 1' has type i32, and at evaluation, the 'i' subexpression
      // evaluates to the i32 value stored in the memory locations for 'i' at the time
      // of evaluation.
      let one: i32 = i + 1;

      // Update the value in the locations referenced by 'i' so they hold the value 2.
      i = one + 1;

      // Update the value in the locations referenced by 'i' so they hold the value 5.
      // The evaluation of the right-hand-side occurs before the assignment takes effect.
      i = i + 3;
    }
  </xmp>
</div>

<div class='example wgsl' heading='Returning a reference returns the value loaded via the reference'>
  <xmp highlight=wgsl>
    var<private> age: i32;
    fn get_age() -> i32 {
      // The type of the expression in the return statement must be 'i32' since it
      // must match the declared return type of the function.
      // The 'age' expression is of type ref<private,i32,read_write>.
      // Apply the Load Rule, since the store type of the reference matches the
      // required type of the expression, and no other type rule applies.
      // The evaluation of 'age' in this context is the i32 value loaded from the
      // memory locations referenced by 'age' at the time the return statement is
      // executed.
      return age;
    }

    fn caller() {
      age = 21;
      // The copy_age constant will get the i32 value 21.
      let copy_age: i32 = get_age();
    }
  </xmp>
</div>

Defining pointers in this way enables two key use cases:

* Using a let-declaration with pointer type, to form a short name for part of the contents of a variable.
* Using a formal parameter of a function to refer to the memory of a variable that is accessible to the [=calling function=].
    * The call to such a function [=shader-creation error|must=] supply a pointer value for that operand.
        This often requires using an [=address-of=] operation (unary `&`) to get a pointer to the variable's contents.

<div class='example wgsl' heading='Using a pointer as a short name for part of a variable'>
  <xmp highlight=wgsl>
    struct Particle {
      position: vec3<f32>,
      velocity: vec3<f32>
    }
    struct System {
      active_index: i32,
      timestep: f32,
      particles: array<Particle,100>
    }
    @group(0) @binding(0) var<storage,read_write> system: System;

    @compute @workgroup_size(1)
    fn main() {
      // Form a pointer to a specific Particle in storage memory.
      let active_particle: ptr<storage,Particle> =
          &system.particles[system.active_index];

      let delta_position: vec3<f32> = (*active_particle).velocity * system.timestep;
      let current_position: vec3<f32>  = (*active_particle).position;
      (*active_particle).position = delta_position + current_position;
    }
  </xmp>
</div>

<div class='example wgsl' heading='Using a pointer as a formal parameter'>
  <xmp highlight=wgsl>
    fn add_one(x: ptr<function,i32>) {
      /* Update the locations for 'x' to contain the next higher integer value,
         (or to wrap around to the largest negative i32 value).
         On the left-hand side, unary '*' converts the pointer to a reference that
         can then be assigned to. It has a read_write access mode, by default.
         /* On the right-hand side:
            - Unary '*' converts the pointer to a reference, with a read_write
              access mode.
            - The only matching type rule is for addition (+) and requires '*x' to
              have type i32, which is the store type for '*x'.  So the Load Rule
              applies and '*x' evaluates to the value stored in the memory for '*x'
              at the time of evaluation, which is the i32 value for 0.
            - Add 1 to 0, to produce a final value of 1 for the right-hand side. */
         Store 1 into the memory for '*x'. */
      *x = *x + 1;
    }

    @compute @workgroup_size(1)
    fn main() {
      var i: i32 = 0;

      // Modify the contents of 'i' so it will contain 1.
      // Use unary '&' to get a pointer value for 'i'.
      // This is a clear signal that the called function has access to the memory
      // for 'i', and may modify it.
      add_one(&i);
      let one: i32 = i;  // 'one' has value 1.
    }
  </xmp>
</div>

### Forming Reference and Pointer Values ### {#forming-references-and-pointers}

A reference value is formed in one of the following ways:

* The [=identifier=] [=resolves|resolving=] to an [=in scope|in-scope=] variable *v* denotes the reference value for *v*'s memory.
* Use the [=indirection=] (unary `*`) operation on a pointer.
* Use a [=named component expression=] on a [=memory view=] to a composite:
    * Given a memory view with a [=vector=] store type, appending a single-letter vector access phrase
        results in a reference to the named component of the vector.
        See [[#component-reference-from-vector-memory-view]].
    * Given a memory view with a [=structure=] store type, appending a member access phrase
        results in a reference to the named member of the structure.
        See [[#struct-access-expr]].
* Use an [=indexing expression=] on a [=memory view=] to a composite:
    * Given a memory view with a [=vector=] store type, appending an array index access phrase
        results in a reference to the indexed component of the vector.
        See [[#component-reference-from-vector-memory-view]].
    * Given a memory view with a [=matrix=] store type, appending an array index access phrase
        results in a reference to the indexed column vector of the matrix.
        See [[#matrix-access-expr]].
    * Given a memory view with an [=array=] store type, appending an array index access phrase
        results in a reference to the indexed element of the array.
        See [[#array-access-expr]].

In all cases, the [=access mode=] of the result is the same as the access mode of the original reference.

<div class='example wgsl' heading='Component reference from a composite reference'>
  <xmp highlight=wgsl>
    struct S {
        age: i32,
        weight: f32
    }
    var<private> person: S;
    // Elsewhere, 'person' denotes the reference to the memory underlying the variable,
    // and will have type ref<private,S,read_write>.

    fn f() {
        var uv: vec2<f32>;
        // For the remainder of this function body, 'uv' denotes the reference
        // to the memory underlying the variable, and will have type
        // ref<function,vec2<f32>,read_write>.

        // Evaluate the left-hand side of the assignment:
        //   Evaluate 'uv.x' to yield a reference:
        //   1. First evaluate 'uv', yielding a reference to the memory for
        //      the 'uv' variable. The result has type ref<function,vec2<f32>,read_write>.
        //   2. Then apply the '.x' vector access phrase, yielding a reference to
        //      the memory for the first component of the vector pointed at by the
        //      reference value from the previous step.
        //      The result has type ref<function,f32,read_write>.
        // Evaluating the right-hand side of the assignment yields the f32 value 1.0.
        // Store the f32 value 1.0 into the storage memory locations referenced by uv.x.
        uv.x = 1.0;

        // Evaluate the left-hand side of the assignment:
        //   Evaluate 'uv[1]' to yield a reference:
        //   1. First evaluate 'uv', yielding a reference to the memory for
        //      the 'uv' variable. The result has type ref<function,vec2<f32>,read_write>.
        //   2. Then apply the '[1]' array index phrase, yielding a reference to
        //      the memory for second component of the vector referenced from
        //      the previous step.  The result has type ref<function,f32,read_write>.
        // Evaluating the right-hand side of the assignment yields the f32 value 2.0.
        // Store the f32 value 2.0 into the storage memory locations referenced by uv[1].
        uv[1] = 2.0;

        var m: mat3x2<f32>;
        // When evaluating 'm[2]':
        // 1. First evaluate 'm', yielding a reference to the memory for
        //    the 'm' variable. The result has type ref<function,mat3x2<f32>,read_write>.
        // 2. Then apply the '[2]' array index phrase, yielding a reference to
        //    the memory for the third column vector pointed at by the reference
        //    value from the previous step.
        //    Therefore the 'm[2]' expression has type ref<function,vec2<f32>,read_write>.
        // The 'let' declaration is for type vec2<f32>, so the declaration
        // statement requires the initializer to be of type vec2<f32>.
        // The Load Rule applies (because no other type rule can apply), and
        // the evaluation of the initializer yields the vec2<f32> value loaded
        // from the memory locations referenced by 'm[2]' at the time the declaration
        // is executed.
        let p_m_col2: vec2<f32> = m[2];

        var A: array<i32,5>;
        // When evaluating 'A[4]'
        // 1. First evaluate 'A', yielding a reference to the memory for
        //    the 'A' variable. The result has type ref<function,array<i32,5>,read_write>.
        // 2. Then apply the '[4]' array index phrase, yielding a reference to
        //    the memory for the fifth element of the array referenced by
        //    the reference value from the previous step.
        //    The result value has type ref<function,i32,read_write>.
        // The let-declaration requires the right-hand-side to be of type i32.
        // The Load Rule applies (because no other type rule can apply), and
        // the evaluation of the initializer yields the i32 value loaded from
        // the memory locations referenced by 'A[4]' at the time the declaration
        // is executed.
        let A_4_value: i32 = A[4];

        // When evaluating 'person.weight'
        // 1. First evaluate 'person', yielding a reference to the memory for
        //    the 'person' variable declared at module scope.
        //    The result has type ref<private,S,read_write>.
        // 2. Then apply the '.weight' member access phrase, yielding a reference to
        //    the memory for the second member of the memory referenced by
        //    the reference value from the previous step.
        //    The result has type ref<private,f32,read_write>.
        // The let-declaration requires the right-hand-side to be of type f32.
        // The Load Rule applies (because no other type rule can apply), and
        // the evaluation of the initializer yields the f32 value loaded from
        // the memory locations referenced by 'person.weight' at the time the
        // declaration is executed.
        let person_weight: f32 = person.weight;

        // Alternatively, references can also be formed from pointers using
        // the same syntax.

        let uv_ptr = &uv;
        // For the remainder of this function body, 'uv_ptr' denotes a pointer
        // to the memory underlying 'uv', and will have the type
        // ptr<function,vec2<f32>,read_write>.

        // Evaluate the left-hand side of the assignment:
        //   Evaluate '*uv_ptr' to yield a reference:
        //   1. First evaluate 'uv_ptr', yielding a pointer to the memory for
        //      the 'uv' variable. The result has type ptr<function,vec2<f32>,read_write>.
        //   2. Then apply the indirection expression operator, yielding a
        //      reference to memory for 'uv'.
        // Evaluating the right-hand side of the assignment yields the vec2<f32> value (1.0, 2.0).
        // Store the value (1.0, 2.0) into the storage memory locations referenced by uv.
        *uv_ptr = vec2f(1.0, 2.0);

        // Evaluate the left-hand side of the assignment:
        //   Evaluate 'uv_ptr.x' to yield a reference:
        //   1. First evaluate 'uv_ptr', yielding a pointer to the memory for
        //      the 'uv' variable. The result has type ptr<function,vec2<f32>,read_write>.
        //   2. Then apply the '.x' vector access phrase, yielding a reference to
        //      the memory for the first component of the vector pointed at by the
        //      reference value from the previous step.
        //      The result has type ref<function,f32,read_write>.
        // Evaluating the right-hand side of the assignment yields the f32 value 1.0.
        // Store the f32 value 1.0 into the storage memory locations referenced by uv.x.
        uv_ptr.x = 1.0;

        // Evaluate the left-hand side of the assignment:
        //   Evaluate 'uv_ptr[1]' to yield a reference:
        //   1. First evaluate 'uv_ptr', yielding a pointer to the memory for
        //      the 'uv' variable. The result has type ptr<function,vec2<f32>,read_write>.
        //   2. Then apply the '[1]' array index phrase, yielding a reference to
        //      the memory for second component of the vector referenced from
        //      the previous step.  The result has type ref<function,f32,read_write>.
        // Evaluating the right-hand side of the assignment yields the f32 value 2.0.
        // Store the f32 value 2.0 into the storage memory locations referenced by uv[1].
        uv_ptr[1] = 2.0;

        let m_ptr = &m;
        // When evaluating 'm_ptr[2]':
        // 1. First evaluate 'm_ptr', yielding a pointer to the memory for
        //    the 'm' variable. The result has type ptr<function,mat3x2<f32>,read_write>.
        // 2. Then apply the '[2]' array index phrase, yielding a reference to
        //    the memory for the third column vector pointed at by the reference
        //    value from the previous step.
        //    Therefore the 'm[2]' expression has type ref<function,vec2<f32>,read_write>.
        // The 'let' declaration is for type vec2<f32>, so the declaration
        // statement requires the initializer to be of type vec2<f32>.
        // The Load Rule applies (because no other type rule can apply), and
        // the evaluation of the initializer yields the vec2<f32> value loaded
        // from the memory locations referenced by 'm[2]' at the time the declaration
        // is executed.
        let p_m_col2: vec2<f32> = m_ptr[2];

        let A_Ptr = &A;
        // When evaluating 'A[4]'
        // 1. First evaluate 'A', yielding a pointer to the memory for
        //    the 'A' variable. The result has type ptr<function,array<i32,5>,read_write>.
        // 2. Then apply the '[4]' array index phrase, yielding a reference to
        //    the memory for the fifth element of the array referenced by
        //    the reference value from the previous step.
        //    The result value has type ref<function,i32,read_write>.
        // The let-declaration requires the right-hand-side to be of type i32.
        // The Load Rule applies (because no other type rule can apply), and
        // the evaluation of the initializer yields the i32 value loaded from
        // the memory locations referenced by 'A[4]' at the time the declaration
        // is executed.
        let A_4_value: i32 = A_ptr[4];

        let person_ptr = &person;
        // When evaluating 'person.weight'
        // 1. First evaluate 'person_ptr', yielding a pointer to the memory for
        //    the 'person' variable declared at module scope.
        //    The result has type ptr<private,S,read_write>.
        // 2. Then apply the '.weight' member access phrase, yielding a reference to
        //    the memory for the second member of the memory referenced by
        //    the reference value from the previous step.
        //    The result has type ref<private,f32,read_write>.
        // The let-declaration requires the right-hand-side to be of type f32.
        // The Load Rule applies (because no other type rule can apply), and
        // the evaluation of the initializer yields the f32 value loaded from
        // the memory locations referenced by 'person.weight' at the time the
        // declaration is executed.
        let person_weight: f32 = person_ptr.weight;
    }
  </xmp>
</div>

A pointer value is formed in one of the following ways:

* Use the [=address-of=] (unary `&`) operator on a reference.
    * The result is a [=valid pointer=] if and only if the original reference is [=valid reference|valid=].
    * The [=originating variable=] of a valid result is defined as the originating variable of the reference.
* If a function [=formal parameter=] has pointer type, then when the function is invoked
    at runtime the uses of the formal parameter denote the pointer value
    provided to the corresponding operand at the [=call site=] in the [=calling function=].
    * The value denoted by the formal parameter (at runtime) is a [=valid pointer=] if and only if
         the pointer value at the call site is [=valid pointer|valid=].
    * The [=originating variable=] of a [=valid pointer=] formal parameter (at runtime) is defined as
        the originating variable of the pointer operand at the call site.

In all cases, the [=access mode=] of the result is the same as the access mode of the original pointer.

<div class='example wgsl' heading='Pointer from a variable'>
  <xmp highlight=wgsl>
    // Declare a variable in the private address space, for storing an f32 value.
    var<private> x: f32;

    fn f() {
        // Declare a variable in the function address space, for storing an i32 value.
        var y: i32;

        // The name 'x' resolves to the module-scope variable 'x',
        // and has reference type ref<private,f32,read_write>.
        // Applying the unary '&' operator converts the reference to a pointer.
        // The access mode is the same as the access mode of the original variable, so
        // the fully specified type is ptr<private,f32,read_write>.  But read_write
        // is the default access mode for function address space, so read_write does not
        // have to be spelled in this case
        let x_ptr: ptr<private,f32> = &x;

        // The name 'y' resolves to the function-scope variable 'y',
        // and has reference type ref<private,i32,read_write>.
        // Applying the unary '&' operator converts the reference to a pointer.
        // The access mode defaults to 'read_write'.
        let y_ptr: ptr<function,i32> = &y;

        // A new variable, distinct from the variable declared at module scope.
        var x: u32;

        // Here, the name 'x' resolves to the function-scope variable 'x' declared in
        // the previous statement, and has type ref<function,u32,read_write>.
        // Applying the unary '&' operator converts the reference to a pointer.
        // The access mode defaults to 'read_write'.
        let inner_x_ptr: ptr<function,u32> = &x;
    }
  </xmp>
</div>

### Comparison with References and Pointers in Other Languages ### {#pointers-other-languages}

This section is informative, not normative.

References and pointers in WGSL are more restricted than in other languages.
In particular:

* In WGSL a reference can't directly be declared as an alias to another reference or variable,
    either as a variable or as a formal parameter.
* In WGSL pointers and references are not [=storable=].
    That is, the content of a WGSL [=variable declaration=] may not contain a pointer or a reference.
* In WGSL a function [=shader-creation error|must not=] return a pointer or reference.
* In WGSL there is no way to convert between integer values and pointer values.
* In WGSL there is no way to forcibly change the type of a pointer value into another pointer type.
    * A composite component reference expression is different:
        it takes a reference to a composite value and yields a reference to
        one of the components or elements inside the composite value.
        These are considered different references in WGSL, even though they may
        have the same machine address at a lower level of implementation abstraction.
* In WGSL there is no way to forcibly change the type of a reference value into another reference type.
* In WGSL there is no way to change the access mode of a pointer or reference.
    * By comparison, C++ automatically converts a non-const pointer to a const pointer,
        and has a `const_cast` to convert a const value to a non-const value.
* In WGSL there is no way to allocate new memory from a "heap".
* In WGSL there is no way to explicitly destroy a variable.
    The memory for a WGSL variable becomes inaccessible only when the variable goes out of scope.

Note: From the above rules, it is not possible to form a "dangling" pointer,
i.e. a pointer that does not reference the memory for a "live"
originating variable.
A [=memory view=] may be an [=invalid memory reference=], but it
[=behavioral requirement|will never=] access [=memory locations=] not associated with the
[=originating variable=] or buffer.

## Texture and Sampler Types ## {#texture-sampler-types}

A <dfn noexport>texel</dfn> is a scalar or vector used as the smallest independently accessible element of a [=texture=].
The word *texel* is short for *texture element*.

A <dfn noexport>texture</dfn> is a collection of texels supporting special operations useful for rendering.
In WGSL, those operations are invoked via texture builtin functions.
See [[#texture-builtin-functions]] for a complete list.

A WGSL texture corresponds to a WebGPU {{GPUTexture}}.

A texture has the following features:

: [=texel format=]
:: The data representation of each texel. See [[#texel-formats]].
: <dfn dfn-for=texture noexport>dimensionality</dfn>
:: The number of dimensions in the grid coordinates, and how the coordinates are interpreted.
    The number of dimensions is 1, 2, or 3.
    Most textures use cartesian coordinates.
    Cube textures have six square faces, and are sampled with
    a three dimensional coordinate interpreted as a direction vector from the origin toward
    the cube centered on the origin.

    See {{GPUTextureViewDimension}}.
: <dfn dfn-for=texture noexport>size</dfn>
:: The extent of grid coordinates along each dimension. This is a function of [=mip level=].
: <dfn dfn-for=texture noexport>mip level count</dfn>
:: The mip level count is at least 1 for [=type/sampled textures=] and [=type/depth textures=], and equal to 1 for [=type/storage textures=].<br>
    <dfn>Mip level</dfn> 0 contains a full size version of the texture.
    Each successive mip level contains a filtered version of the previous mip level
    at half the size (within rounding) of the previous mip level.<br>
    When sampling a texture, an explicit or implicitly-computed level-of-detail is used
    to select the mip levels from which to read texel data.  These are then combined via
    filtering to produce the sampled value.
: <dfn dfn-for=texture noexport>arrayed</dfn>
:: Whether the texture is arrayed.
    * A non-arrayed texture is a grid of texels.
    * An arrayed texture is a homogeneous array of grids of texels.
: <dfn dfn-for=texture noexport>array size</dfn>
:: The number of homogeneous grids, if the texture is [=texture/arrayed=].
: <dfn dfn-for=texture noexport>sample count</dfn>
:: The number of samples, if the texture is [[#multisampled-texture-type|multisampled]].

Each texel in a texture is associated with a unique <dfn noexport>logical texel address</dfn>,
which is an integer tuple having:
* A [=mip level=] in [0, [=texture/mip level count=]).
* A number of components, controlled by the [=texture/dimensionality=], with each
    component value in [0, *S*<sub>i</sub>), where *S*<sub>i</sub> is the [=texture/size=] in the *i*'th component.
* An array index in [0, [=texture/array size=]), if the texture is [=texture/arrayed=].
    Note that [=texture/size=] is a function of [=mip level=].
* A sample index in [0, [=texture/sample count=]), if the texture is [[#multisampled-texture-type|multisampled]].

A texture's physical organization is typically optimized for rendering operations.
To achieve this, many details are hidden from the programmer, including data layouts, data types, and
internal operations that cannot be expressed directly in the shader language.

As a consequence, a shader does not have direct access to the texel memory within a [=texture resource|texture variable=].
Instead, access is mediated through an opaque handle:

* Within the shader:
    * Declare a module-scope variable
        where the [=store type=] is one of the texture types described in later sections.
        The variable stores an opaque handle to the underlying texture memory, and is
        automatically placed in the [=address spaces/handle=] address space.
    * Inside a function, call one of the texture builtin functions, and provide
        the texture variable or function parameter as the builtin function's
        first parameter.
* When constructing the WebGPU pipeline, the texture variable's store type and binding
    [=shader-creation error|must=] be compatible with the corresponding bind group layout entry.

In this way, the set of supported operations for a texture type
is determined by the availability of [[#texture-builtin-functions|texture built-in functions]]
having a [=formal parameter=] with that texture type.

Note: The handle stored by a texture variable cannot be changed by the shader.
That is, the variable is read-only, even if the underlying texture to which it provides
access may be mutable (e.g. a write-only [=type/storage texture=]).

The <dfn>texture types</dfn> are the set of types defined in:
* [[#sampled-texture-type]]
* [[#multisampled-texture-type]]
* [[#external-texture-type]]
* [[#texture-storage]]
* [[#texture-depth]]

A [=sampler=] is an opaque handle that controls how [=texels=] are accessed
from a [=type/sampled texture=] or a [=type/depth texture=].

A WGSL sampler maps to a WebGPU {{GPUSampler}}.

Texel access is controlled via several properties of the sampler:

: addressing mode
:: Controls how texture boundaries and out-of-bounds
    coordinates are resolved.
    The addressing mode for each texture dimension can be set independently.
    See WebGPU {{GPUAddressMode}}.
: filter mode
:: Controls which texels are accessed to produce the final result.
    Filtering can either use the nearest texel or interpolate between multiple
    texels.
    Multiple filter modes can be set independently.
    See WebGPU {{GPUFilterMode}}.
: LOD clamp
:: Controls the min and max levels of details that are accessed.
: comparison
:: Controls the type of comparison done for [=type/sampler_comparison|comparison sampler=].
    See WebGPU {{GPUCompareFunction}}.
: max anisotropy
:: Controls the maximum anisotropy value used by the sampler.

Samplers cannot be created in WGSL modules and their state (e.g. the
properties listed above) are immutable within a shader and can only be set by
the WebGPU API.

It is a [=pipeline-creation error=] if a filtering sampler (i.e. any sampler
using interpolative filtering) is used with texture that has a non-filterable
format.

Note: The handle stored by a sampler variable cannot be changed by the shader.

### Texel Formats ### {#texel-formats}

In WGSL, certain texture types are parameterized by texel format.

A <dfn noexport>texel format</dfn> is characterized by:

: <dfn noexport>channels</dfn>
:: Each channel contains a scalar.
    A texel format has up to four channels: `r`, `g`, `b`, and `a`,
    normally corresponding to the concepts of red, green, blue, and alpha channels.
: <dfn noexport>channel format</dfn>
:: The number of bits in the channel, and how those bits are interpreted.

Each texel format in WGSL corresponds to a WebGPU {{GPUTextureFormat}}
with the same name.

Only certain texel formats are used in WGSL source code.
The channel formats used to define those texel formats are listed in the
<dfn dfn>Channel Formats</dfn> table.
The second last column specifies the conversion from the stored channel bits to the value used in the shader.
This is also known as the <dfn noexport>channel transfer function</dfn>, or CTF.
The last column specifies the conversion from the shader value to the stored channel bits.
This is also known as the <dfn noexport>inverse channel transfer function</dfn>, or ICTF.

Note: The channel transfer function for 8unorm maps {0,...,255} to the floating point interval [0.0, 1.0].

Note: The channel transfer function for 8snorm maps {-128,...,127} to the floating point interval [-1.0, 1.0].

<table class='data'>
  <caption>Channel Formats</caption>
  <thead>
    <tr><th>Channel format
        <th>Number of stored bits
        <th>Interpretation of stored bits
        <th>Shader type
        <th style="width:15%">Shader value (Channel Transfer Function)
        <th style="width:30%">Write value `T` (Inverse Channel Transfer Function)
  </thead>
  <tr><td>8unorm<td>8<td>unsigned integer |v| &isinv; {0,...,255}<td>f32<td> |v| &div; 255<td> max(0, min(1, `T`))
  <tr><td>8snorm<td>8<td>signed integer |v| &isinv; {-128,...,127}<td>f32<td> |v| &div; 127<td> max(-1, min(1, `T`))
  <tr><td>8uint<td>8<td>unsigned integer |v| &isinv; {0,...,255}<td>u32<td> |v|<td> min(255, `T`)
  <tr><td>8sint<td>8<td>signed integer |v| &isinv; {-128,...,127}<td>i32<td> |v|<td> max(-128, min(127, `T`))
  <tr><td>16uint<td>16<td>unsigned integer |v| &isinv; {0,...,65535}<td>u32<td> |v|<td> min(65535, `T`)
  <tr><td>16sint<td>16<td>signed integer |v| &isinv; {-32768,...,32767}<td>i32<td> |v|<td> max(-32768, min(32767, `T`))
  <tr><td>16float<td>16<td>[[!IEEE-754|IEEE-754]] binary16 16-bit floating point value |v|, with 1 sign bit, 5 exponent bits, 10 mantissa bits<td>f32<td>|v|<td>`quantizeToF16(T)`
  <tr><td>32uint<td>32<td>32-bit unsigned integer value |v|<td>u32<td>|v|<td>`T`
  <tr><td>32sint<td>32<td>32-bit signed integer value |v|<td>i32<td>|v|<td>`T`
  <tr><td>32float<td>32<td>[[!IEEE-754|IEEE-754]] binary32 32-bit floating point value |v|<td>f32<td>|v|<td>`T`
</table>

The texel formats listed in the
<dfn lt="storage-texel-formats">Texel Formats for Storage Textures</dfn> table
correspond to the [[WebGPU#plain-color-formats|WebGPU plain color formats]]
which support the WebGPU {{GPUTextureUsage/STORAGE_BINDING}} usage.
These texel formats are used to parameterize the [=type/storage texture=] types defined
in [[#texture-storage]].

When the texel format does not have all four channels, then:

* When reading the texel, the [=channel transfer function=] is applied [=component-wise=]:
    * If the texel format has no green channel, then the second component of the shader value is 0.
    * If the texel format has no blue channel, then the third component of the shader value is 0.
    * If the texel format has no alpha channel, then the fourth component of the shader value is 1.
* When writing the texel, the [=inverse channel transfer function=] is applied [=component-wise=]
    and shader value components for missing channels are ignored.

The last column in the table below uses the format-specific
[=channel transfer function=] from the [=channel formats=] table.

<table class='data'>
  <caption>Texel Formats for Storage Textures</caption>
  <thead>
    <tr><th>Texel format
        <th>Channel format
        <th>Channels in memory order
        <th style="width:50%">Corresponding shader value
  </thead>
  <tr><td><dfn for="texel format">rgba8unorm</dfn><td>8unorm<td>r, g, b, a<td>vec4&lt;f32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba8snorm</dfn><td>8snorm<td>r, g, b, a<td>vec4&lt;f32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba8uint</dfn><td>8uint<td>r, g, b, a<td>vec4&lt;u32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba8sint</dfn><td>8sint<td>r, g, b, a<td>vec4&lt;i32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba16uint</dfn><td>16uint<td>r, g, b, a<td>vec4&lt;u32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba16sint</dfn><td>16sint<td>r, g, b, a<td>vec4&lt;i32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba16float</dfn><td>16float<td>r, g, b, a<td>vec4&lt;f32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">r32uint</dfn><td>32uint<td>r<td>vec4&lt;u32&gt;(CTF(r), 0u, 0u, 1u)
  <tr><td><dfn for="texel format">r32sint</dfn><td>32sint<td>r<td>vec4&lt;i32&gt;(CTF(r), 0, 0, 1)
  <tr><td><dfn for="texel format">r32float</dfn><td>32float<td>r<td>vec4&lt;f32&gt;(CTF(r), 0.0, 0.0, 1.0)
  <tr><td><dfn for="texel format">rg32uint</dfn><td>32uint<td>r, g<td>vec4&lt;u32&gt;(CTF(r), CTF(g), 0.0, 1.0)
  <tr><td><dfn for="texel format">rg32sint</dfn><td>32sint<td>r, g<td>vec4&lt;i32&gt;(CTF(r), CTF(g), 0.0, 1.0)
  <tr><td><dfn for="texel format">rg32float</dfn><td>32float<td>r, g<td>vec4&lt;f32&gt;(CTF(r), CTF(g), 0.0, 1.0)
  <tr><td><dfn for="texel format">rgba32uint</dfn><td>32uint<td>r, g, b, a<td>vec4&lt;u32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba32sint</dfn><td>32sint<td>r, g, b, a<td>vec4&lt;i32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">rgba32float</dfn><td>32float<td>r, g, b, a<td>vec4&lt;f32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
  <tr><td><dfn for="texel format">bgra8unorm</dfn><td>8unorm<td>b, g, r, a<td>vec4&lt;f32&gt;(CTF(r), CTF(g), CTF(b), CTF(a))
</table>

WGSL [=predeclared|predeclares=] an [=enumerant=] for each of the texel formats in the table.

### Sampled Texture Types ### {#sampled-texture-type}

A <dfn noexport dfn-for='type'>sampled texture</dfn> is capable
of being [=memory access|accessed=] in conjunction with a [=type/sampler=].
It can also be accessed without the use of a sampler.
Sampled textures only allow [=read accesses=].

The [=texel format=] is the {{GPUTexture/format}} attribute of the
{{GPUTexture}} bound to the texture variable.
WebGPU [$validating shader binding|validates$] compatibility between the
texture, the {{GPUTextureBindingLayout/sampleType}} of the bind group layout,
and the [=sampled type=] of the texture variable.

The texture is parameterized by a <dfn noexport>sampled type</dfn> and
[=shader-creation error|must=] be `f32`, `i32`, or `u32`.

<table class='data'>
  <thead>
    <tr><th>Type<th>[=texture/Dimensionality=]<th>[=texture/Arrayed=]
  </thead>
  <tr><td><dfn noexport dfn-for='type'>texture_1d</dfn><*T*>
      <td>{{GPUTextureViewDimension/"1d"|1D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_2d</dfn><*T*>
      <td>{{GPUTextureViewDimension/"2d"|2D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_2d_array</dfn><*T*>
      <td>{{GPUTextureViewDimension/"2d-array"|2D}}
      <td>Yes
  <tr><td><dfn noexport dfn-for='type'>texture_3d</dfn><*T*>
      <td>{{GPUTextureViewDimension/"3d"|3D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_cube</dfn><*T*>
      <td>{{GPUTextureViewDimension/"cube"|Cube}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_cube_array</dfn><*T*>
      <td>{{GPUTextureViewDimension/"cube-array"|Cube}}
      <td>Yes
</table>

* *T* is the [=sampled type=].
* The parameterized type for the images is the type after conversion from sampling.
    E.g. you can have an image with texels with 8bit unorm components, but when you sample
    them you get a 32-bit float result (or vec-of-f32).

### Multisampled Texture Types ### {#multisampled-texture-type}

A <dfn noexport dfn-for='type'>multisampled texture</dfn> has a
[=texture/sample count=] of 1 or more.
Despite the name, it cannot be used with a [=sampler=].
It effectively stores multiple [=texels=] worth of data per
[=logical texel address=] if the sample index is ignored.

The [=texel format=] is the {{GPUTexture/format}} attribute of the
{{GPUTexture}} bound to the texture variable.
WebGPU [$validating shader binding|validates$] compatibility between the
texture, the {{GPUTextureBindingLayout/sampleType}} of the bind group layout,
and the [=sampled type=] of the texture variable.

The texture is parameterized by a [=sampled type=] and
[=shader-creation error|must=] be `f32`, `i32`, or `u32`.

<table class='data'>
  <thead>
    <tr><th>Type<th>[=texture/Dimensionality=]<th>[=texture/Arrayed=]
  </thead>
  <tr><td><dfn noexport dfn-for='type'>texture_multisampled_2d</dfn><*T*>
      <td>{{GPUTextureViewDimension/"2d"|2D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_depth_multisampled_2d</dfn>
      <td>{{GPUTextureViewDimension/"2d"|2D}}
      <td>No
</table>

* *T* is the [=sampled type=].

### External Sampled Texture Types ### {#external-texture-type}

An <dfn noexport dfn-for='type'>External texture</dfn> is an opaque
two-dimensional float-[=type/sampled texture=] type similar to `texture_2d<f32>` but
potentially with a different representation.
It can be read using [[#textureload|textureLoad]] or
[[#textureSampleBaseClampToEdge|textureSampleBaseClampToEdge]] built-in
functions, which handle these different representations.

See [[WebGPU#gpuexternaltexture]].

<table class='data'>
  <thead>
    <tr><th>Type<th>[=texture/Dimensionality=]<th>[=texture/Arrayed=]
  </thead>
  <tr><td><dfn noexport dfn-for='type'>texture_external</dfn>
      <td>{{GPUTextureViewDimension/"2d"|2D}}
      <td>No
</table>

### Storage Texture Types ### {#texture-storage}

A <dfn noexport dfn-for='type'>storage texture</dfn> supports [=memory access|accessing=]
individual texel values without the use of a sampler.

* A <dfn noexport dfn-for='type'>write-only storage texture</dfn>
     supports [=write access|writing=] individual texels, with automatic
     conversion of the shader value to a stored texel value.
* A <dfn noexport dfn-for='type'>read-only storage texture</dfn>
     supports [=read access|reading=] individual texels, with automatic
     conversion of the stored texel value to a shader texel value.
* A <dfn noexport dfn-for='type'>read-write storage texture</dfn>
     supports [=read access|reading=] and [=write access|writing=] individual
     texels, with automatic conversion between shader and stored texel values.

A storage texture type [=shader-creation error|must=] be parameterized by one of the
[=storage-texel-format|texel formats for storage textures=].
The texel format determines the conversion function as specified in [[#texel-formats]].

When writing texels to a storage texture the *inverse* of the conversion function is
used to convert the shader value to the stored texel.

<table class='data'>
  <thead>
    <tr><th>Type<th>[=texture/Dimensionality=]<th>[=texture/Arrayed=]
  </thead>
  <tr><td><dfn noexport dfn-for='type'>texture_storage_1d</dfn><*Format*, *Access*>
      <td>{{GPUTextureViewDimension/"1d"|1D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_storage_2d</dfn><*Format*, *Access*>
      <td>{{GPUTextureViewDimension/"2d"|2D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_storage_2d_array</dfn><*Format*, *Access*>
      <td>{{GPUTextureViewDimension/"2d-array"|2D}}
      <td>Yes
  <tr><td><dfn noexport dfn-for='type'>texture_storage_3d</dfn><*Format*, *Access*>
      <td>{{GPUTextureViewDimension/"3d"|3D}}
      <td>No
</table>

* *Format* [=shader-creation error|must=] be an [=enumerant=] for one of the [=storage-texel-formats|texel formats for storage textures=]
* *Access* [=shader-creation error|must=] be an [=enumerant=] for one of the [=access modes=].

### Depth Texture Types ### {#texture-depth}

A <dfn noexport dfn-for='type'>depth texture</dfn> is capable
of being [=memory access|accessed=] in conjunction with a [=type/sampler_comparison=].
It can also be accessed without the use of a sampler.
Depth textures only allow [=read accesses=].

The [=texel format=] of the texture is defined in the {{GPUTextureBindingLayout}}.

<table class='data'>
  <thead>
    <tr><th>Type<th>[=texture/Dimensionality=]<th>[=texture/Arrayed=]
  </thead>
  <tr><td><dfn noexport dfn-for='type'>texture_depth_2d</dfn>
      <td>{{GPUTextureViewDimension/"2d"|2D}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_depth_2d_array</dfn>
      <td>{{GPUTextureViewDimension/"2d-array"|2D}}
      <td>Yes
  <tr><td><dfn noexport dfn-for='type'>texture_depth_cube</dfn>
      <td>{{GPUTextureViewDimension/"cube"|Cube}}
      <td>No
  <tr><td><dfn noexport dfn-for='type'>texture_depth_cube_array</dfn>
      <td>{{GPUTextureViewDimension/"cube-array"|Cube}}
      <td>Yes
</table>

### Sampler Type ### {#sampler-type}

A <dfn>sampler</dfn> mediates access to a [=type/sampled texture=] or a
[=type/depth texture=], by performing a combination of:
* coordinate transformation.
* optionally modifying mip-level selection.
* for a [=type/sampled texture=], optionally filtering retrieved texel values.
* for a [=type/depth texture=], determining the comparison function applied to the retrieved texel.

A <dfn noexport>sampler types</dfn> are:
* [=type/sampler=]
* [=type/sampler_comparison=]

<table class='data'>
  <thead>
    <tr><th>Type<th>Description
  </thead>
  <tr algorithm="sampler type">
    <td><dfn dfn-for="type">sampler</dfn>
    <td>Sampler. Mediates access to a [=type/sampled texture=].</td>
  <tr algorithm="comparison sampler type">
    <td><dfn dfn-for="type">sampler_comparison</dfn>
    <td>Comparison sampler.
        Mediates access to a [=type/depth texture=].</td>
</table>

Samplers are parameterized when created in the WebGPU API.
They cannot be modified by a WGSL module.

Samplers can only be used by the [[#texture-builtin-functions|texture built-in functions]].

<pre class='def'>
sampler
sampler_comparison
</pre>

## AllTypes Type ## {#alltypes-type}

The <dfn noexport>AllTypes</dfn> type is the set of all WGSL [=types=].

There is no way to write the AllTypes type in WGSL source.

See [[#predeclared-types]] for the list of all [=predeclared=] types and [=type-generators=].

<div class=note>
<span class=marker>Note:</span>A type is not a value in an ordinary sense.
It is not data that is manipulated by a shader at runtime.

<p>
Instead, the AllTypes type exists so [=type checking=] rules will apply to any phrase that *may* contain an ordinary value.
WGSL makes the rules consistent by defining a type to be a kind of value, and allowing an expression to denote a type.

<p>
The motivating case is a [=template parameter=], which in various contexts may denote several kinds of things,
including a [=type=], an [=enumerant=], or a [=plain type|plain=] value.
In particular, the [=syntax/template_arg_expression=] grammar rule expands to the [=syntax/expression=] grammar nonterminal.
</div>

## Type Aliases ## {#type-aliases}

A <dfn noexport>type alias</dfn> declares a new name for an existing type.
The declaration [=shader-creation error|must=] appear at [=module scope=], and its [=scope=] is the entire program.

When type *T* is defined as a [=type alias=] for a structure type *S*,
all properties of the members of *S*, including attributes, carry over to the members of *T*.

<pre class=include>
path: syntax/type_alias_decl.syntax.bs.include
</pre>

<div class='example wgsl global-scope' heading='Type Alias'>
  <xmp highlight=wgsl>
    alias Arr = array<i32, 5>;

    alias RTArr = array<vec4<f32>>;

    alias single = f32;     // Declare an alias for f32
    const pi_approx: single = 3.1415;
    fn two_pi() -> single {
      return single(2) * pi_approx;
    }
  </xmp>
</div>

## Type Specifier Grammar ## {#type-specifiers}

See [[#type-expr]].

<pre class=include>
path: syntax/type_specifier.syntax.bs.include
</pre>

<pre class=include>
path: syntax/template_elaborated_ident.syntax.bs.include
</pre>

Note: An [=expression=] can also denote a type, by expanding via the [=syntax/primary_expression=] grammar rule to [=syntax/template_elaborated_ident=],
and via [[#parenthesized-expressions|parenthesization]].

## Predeclared Types and Type-Generators Summary ## {#predeclared-types}

The [=predeclared=] [=types=] that can be spelled in WGSL source are:
* [=bool=]
* [=f16=]
* [=f32=]
* [=i32=]
* [=type/sampler=]
* [=type/sampler_comparison=]
* [=type/texture_depth_2d=]
* [=type/texture_depth_2d_array=]
* [=type/texture_depth_cube=]
* [=type/texture_depth_cube_array=]
* [=type/texture_depth_multisampled_2d=]
* [=type/texture_external=]
* [=u32=]

WGSL also predeclares the return types for the [[#frexp-builtin|frexp]],
[[#modf-builtin|modf]], and [[#atomic-rmw|atomicCompareExchangeWeak]] built-in
functions.
However, they cannot be spelled in WGSL source.

The predeclared [=type-generators=] are listed in the following table:
<table class=data>
<caption>
  Predeclared type generators
</caption>
<thead>
  <tr><th>Predeclared type-generator<th>Cross-reference
</thead>
  <tr><td>array<td>See [[#array-types]]
  <tr><td>atomic<td>See [[#atomic-types]]
  <tr><td>mat2x2<td rowspan=9>See [[#matrix-types]], which also lists
     predeclared [=type aliases|aliases=] for matrix types.

     Note: These are also used in [=value constructor=] expressions
     to create matrices.
  <tr><td>mat2x3
  <tr><td>mat2x4
  <tr><td>mat3x2
  <tr><td>mat3x3
  <tr><td>mat3x4
  <tr><td>mat4x2
  <tr><td>mat4x3
  <tr><td>mat4x4
  <tr><td>ptr<td>See [[#ref-ptr-types]]
  <tr><td>texture_1d<td rowspan=6>See [[#sampled-texture-type]]
  <tr><td>texture_2d
  <tr><td>texture_2d_array
  <tr><td>texture_3d
  <tr><td>texture_cube
  <tr><td>texture_cube_array
  <tr><td>texture_multisampled_2d<td>See [[#multisampled-texture-type]]
  <tr><td>texture_storage_1d<td rowspan=4>See [[#texture-storage]]
  <tr><td>texture_storage_2d
  <tr><td>texture_storage_2d_array
  <tr><td>texture_storage_3d
  <tr><td>vec2<td rowspan=3>See [[#vector-types]], which also lists
     predeclared [=type aliases|aliases=] for vector types.

     Note: These are also used in [=value constructor=] expressions
     to create vectors.
  <tr><td>vec3
  <tr><td>vec4
</table>

# Variable and Value Declarations # {#var-and-value}

[=variable declaration|Variable=] and [=value declaration|value=] declarations
provide names for data values.

A <dfn noexport>value declaration</dfn> creates a name for a value, and that
value is immutable once it has been declared.
The four kinds of value declarations are `const`, `override`, `let`, and formal parameter declarations,
further described below (see [[#value-decls]]).

A <dfn noexport>variable declaration</dfn> creates a name for [=memory locations=]
for storing a value; the value stored there may be updated, if the variable has
a [=access/read_write=] access mode.
There is one kind of variable declaration, `var`, but it has options for
[=address space=] and [=access modes=] in various combinations, described
below (see [[#var-decls]]).

Note: A value declaration does not have associated memory locations. For
example, no WGSL expression can form a pointer to the value.

A declaration appearing outside of any function definition is at [=module scope=].
Its name is [=in scope=] for the entire program.

A declaration appearing within a function definition is in <dfn
noexport>function scope</dfn>.
The name is available for use in the statement immediately after its
declaration until the end of the brace-delimited list of statements immediately
enclosing the declaration.
A function-scope declaration is a [=dynamic context=].

Variable and value declarations have a similar overall syntax:
<xmp highlight=wgsl>
  // Specific value declarations.
               const    name [: type]  = initializer ;
  [attribute]* override name [: type] [= initializer];
               let      name [: type]  = initializer ;

  // General variable form.
  [attribute]* var[<address_space[, access_mode]>] name [: type] [= initializer];

  // Specific variable declarations.
  // Function scope.
               var[<function>] name [: type] [= initializer];

  // Module scope.
               var<private>    name [: type] [= initializer];
               var<workgroup>  name : type;
  [attribute]+ var<uniform>    name : type;
  [attribute]+ var             name : texture_type;
  [attribute]+ var             name : sampler_type;
  [attribute]+ var<storage[, access_mode]> name : type;
</xmp>

Each such declaration [=shader-creation error|must=] have an explicitly
specified type or an initializer.
Both a type and an initializer may be specified.
Each such declaration determines the type for the associated data value, known
as the <dfn noexport>effective-value-type</dfn> for the declaration.
The effective-value-type of the declaration is:
* The declared type, if explicitly specified.
* Otherwise, if the initializer expression has type `T`:
    * For a `const` declaration, the effective-value-type is `T` itself.
    * For a `override`, `let`, or `var` declaration, the effective-value-type
        is the [=concretization=] of `T`.

Each kind of value or variable declaration may place additional constraints on
the form of the initializer expression, if present, and on the
effective-value-type.

<table class='data'>
<caption>
  Variable and Value Declaration Feature Summary.
</caption>
<thead>
  <tr><th>Declaration
      <th>Mutability
      <th>Scope
      <th>[=Effective-value-type=]<sup>1</sup>
      <th>Initializer Support
      <th>Initializer Expression<sup>2</sup>
      <th>Part of Resource Interface
</thead>
<tr><td>[=const-declaration|const=]
    <td>Immutable
    <td>[=module scope|Module=] or [=function scope|function=]
    <td>[=Constructible=] ([=type/concrete|Concrete=] or [=type/abstract|abstract=])
    <td>Required
    <td>[=const-expression=]
    <td>No

<tr><td>[=override-declaration|override=]
    <td>Immutable
    <td>[=module scope|Module=]
    <td>[=type/concrete|Concrete=] [=scalar=]
    <td>Optional<sup>3</sup>
    <td>[=const-expression=] or [=override-expression=]
    <td>No<sup>4</sup>

<tr><td>[=let-declaration|let=]
    <td>Immutable
    <td>[=function scope|Function=]
    <td>[=type/concrete|Concrete=] [=constructible=] or [=pointer type=]
    <td>Required
    <td>[=const-expression=], [=override-expression=], or [=runtime expression=]
    <td>No

<tr><td class="nowrap">
        [=variable|var=]&lt;[=address spaces/storage=], read&gt;<br>
        [=variable|var=]&lt;[=address spaces/storage=]&gt;
    <td>Immutable
    <td>[=module scope|Module=]
    <td>[=type/concrete|Concrete=] [=host-shareable=]
    <td>Disallowed
    <td>
    <td>Yes.<br>[=storage buffer=]

<tr><td class="nowrap">
        [=variable|var=]&lt;[=address spaces/storage=], read_write&gt;<sup>5,6</sup>
    <td>Mutable
    <td>[=module scope|Module=]
    <td>[=type/concrete|Concrete=] [=host-shareable=]
    <td>Disallowed
    <td>
    <td>Yes.<br>[=storage buffer=]

<tr><td>[=variable|var=]&lt;[=address spaces/uniform=]&gt;
    <td>Immutable
    <td>[=module scope|Module=]
    <td>[=type/concrete|Concrete=] [=constructible=] [=host-shareable=]
    <td>Disallowed
    <td>
    <td>Yes.<br>[=uniform buffer=]

<tr><td>[=variable|var=]<sup>6</sup>
    <td>Immutable<sup>7</sup>
    <td>[=module scope|Module=]
    <td>[=texture type|Texture=]
    <td>Disallowed
    <td>
    <td>Yes.<br>[=texture resource=]

<tr><td>[=variable|var=]
    <td>Immutable
    <td>[=module scope|Module=]
    <td>[=sampler type|Sampler=]
    <td>Disallowed
    <td>
    <td>Yes.<br>[=sampler resource=]

<tr><td>[=variable|var=]&lt;[=address spaces/workgroup=]&gt;<sup>6,8</sup>
    <td>Mutable
    <td>[=module scope|Module=]
    <td>[=type/concrete|Concrete=] [=plain type=] with a [=fixed footprint=]<sup>9</sup>
    <td>Disallowed<sup>10</sup>
    <td>
    <td>No

<tr><td>[=variable|var=]&lt;[=address spaces/private=]&gt;
    <td>Mutable
    <td>[=module scope|Module=]
    <td>[=type/concrete|Concrete=] [=constructible=]
    <td>Optional<sup>10</sup>
    <td>[=const-expression=] or [=override-expression=]
    <td>No

<tr><td>[=variable|var=]&lt;[=address spaces/function=]&gt;<br>
        [=variable|var=]
    <td>Mutable
    <td>[=function scope|Function=]
    <td>[=type/concrete|Concrete=] [=constructible=]
    <td>Optional<sup>10</sup>
    <td>[=const-expression=], [=override-expression=], or [=runtime expression=]
    <td>No

</table>
1. Only [=const-declarations=] can be [=type/abstract=] types, and only when
    the type is not explicitly specified.
2. The type of the expression must be [=feasible automatic conversion|feasibly
    converted=] to the [=effective-value-type=].
3. If an initializer is not specified, a value must be provided at [=pipeline
    creation|pipeline-creation time=].
4. [=Override-declarations=] are part of the shader interface, but are not
    bound resources.
5. [=Storage buffers=] and [=type/storage textures=] with an access mode other
    than [=access/read=] cannot be [=statically accessed=] in a [=vertex shader
    stage=].
    See WebGPU {{GPUDevice/createBindGroupLayout()}}.
6. [=Atomic types=] can only appear in mutable storage buffers or workgroup
    variables.
7. The data in [[#texture-storage|storage textures]] with a [=access/write=]
    or [=access/read_write=] [=access mode=] is mutable, but can only be
    modified via [[#texturestore|textureStore]] built-in function.
    The variable itself cannot be modified.
8. Variables in the [=address spaces/workgroup=] address space can only be
    [=statically accessed=] in a [=compute shader stage=].
9. The [=element count=] of the outermost [=array=] may be an
    [=override-expression=].
10. If there is no initializer, the variable is [=default initial value|default
    initialized=].

## Variables vs Values ## {#var-vs-value}

[=Variable declarations=] are the only mutable data in a WGSL module.
[=Value declarations=] are always immutable.
Variables can be the basis of [=reference type|reference=] and [=pointer
type|pointer=] values because variables have associated [=memory locations=],
whereas a value declaration cannot be the basis of a pointer or reference
value.

Using variables is generally more expensive than using value declarations,
because using a variable requires extra operations to [=read access|read=] or
[=write access|write=] to the [=memory locations=] associated with the variable.

Generally speaking, an author should prefer using declarations in the following
order, with the most preferred option listed first:
* [=const-declaration=]
* [=override-declaration=]
* [=let-declaration=]
* [=variable declaration=]

This will generally result in the best overall performance of a shader.

## Value Declarations ## {#value-decls}

When an [=identifier=] [=resolves=] to a [=value declaration=], the identifier
denotes that value.

WGSL provides multiple kinds of value declarations.
The value for each kind of declaration is fixed at a different point in the
[[#shader-lifecycle|shader lifecycle]].
The different kinds of value declarations and when their values are fixed are:
* [=const-declarations=], at [=shader module creation|shader-creation time=]
* [=override-declarations=], at [=pipeline creation|pipeline-creation time=]
* [=let-declarations=], when they are executed
* [=formal parameter=] declarations, when the associated [=function call=] argument is executed

Note: [=Formal parameters=] are described in [[#functions]].

### `const` Declarations ### {#const-decls}

A <dfn noexport>const-declaration</dfn> specifies a name for a data value that
is fixed at [=shader module creation|shader-creation time=].
Each const-declaration requires an initializer.
A const-declaration can be declared in [=module scope|module=] or [=function
scope|function=] scope.
The initializer expression [=shader-creation error|must=] be a
[=const-expression=].
The type of a const-declaration must be a [=type/concrete=] or
[=type/abstract=] [=constructible=] type.
const-declarations are the only declarations where the [=effective-value-type=]
may be [=type/abstract=].

Note: Since [=abstract numeric types=] cannot be spelled in WGSL, they can only
be used via type inference.

<div class='example wgsl global-scope' heading='const-declarations at module scope'>
  <xmp highlight=wgsl>
    const a = 4;                  // AbstractInt with a value of 4.
    const b : i32 = 4;            // i32 with a value of 4.
    const c : u32 = 4;            // u32 with a value of 4.
    const d : f32 = 4;            // f32 with a value of 4.
    const e = vec3(a, a, a);      // vec3 of AbstractInt with a value of (4, 4, 4).
    const f = 2.0;                // AbstractFloat with a value of 2.
    const g = mat2x2(a, f, a, f); // mat2x2 of AbstractFloat with a value of:
                                  // ((4.0, 2.0), (4.0, 2.0)).
                                  // The AbstractInt a converts to AbstractFloat.
                                  // An AbstractFloat cannot convert to AbstractInt.
    const h = array(a, f, a, f);  // array of AbstractFloat with 4 components:
                                  // (4.0, 2.0, 4.0, 2.0).
  </xmp>
</div>

### `override` Declarations ### {#override-decls}

An <dfn noexport>override-declaration</dfn> specifies a name for a
[=pipeline-overridable=] constant value.
An override-declaration [=shader-creation error|must=] only be declared at
[=module scope=].
The value of a <dfn noexport>pipeline-overridable</dfn> constant is fixed at
[=pipeline creation|pipeline-creation time=].
The value is one provided by the WebGPU pipeline-creation method, if
specified, and otherwise is the value of its [=concretization of a
value|concretized=] initializer expression.
The [=effective-value-type=] of an override-declaration must be a [=type/concrete=]
[=scalar=] type.

An initializer expression is optional.
If present, it must be an [=override-expression=] and represents the <dfn
noexport>pipeline-overridable constant default value</dfn>.
If no initializer is specified, it is a [=pipeline-creation error=] if a value
is not provided at pipeline-creation time.

If the declaration has an [=attribute/id=] attribute applied, the literal
operand is known as the <dfn noexport>pipeline constant ID</dfn>, and must be a
unique integer between 0 and 65535 inclusive.
That is, two override-declarations must not use the same pipeline constant ID.

The application can specify its own value for an override-declaration at
[=pipeline creation|pipeline-creation time=].
The pipeline creation API accepts a mapping from overridable constants to a
value of the constant’s type.
The constant is identified by a <dfn noexport>pipeline-overridable constant
identifier string</dfn>, which is the base-10 representation of the [=pipeline
constant ID=] if specified, and otherwise the declared [=name=] of the constant.

<div class='example wgsl global-scope' heading='Module constants, pipeline-overrideable'>
  <xmp highlight=wgsl>
    @id(0)    override has_point_light: bool = true;  // Algorithmic control
    @id(1200) override specular_param: f32 = 2.3;     // Numeric control
    @id(1300) override gain: f32;                     // Must be overridden
              override width: f32 = 0.0;              // Specified at the API level using
                                                      // the name "width".
              override depth: f32;                    // Specified at the API level using
                                                      // the name "depth".
                                                      // Must be overridden.
              override height = 2 * depth;            // The default value
                                                      // (if not set at the API level),
                                                      // depends on another
                                                      // overridable constant.

  </xmp>
</div>


### `let` Declarations ### {#let-decls}

A <dfn noexport>let-declaration</dfn> specifies a name for a value that is
fixed each time the statement is executed at runtime.
A let-declaration must only be declared in [=function scope=], and as such, is
a [=dynamic context=].
A let-declaration must have an initializer expression.
The value is the [=concretization of a value|concretized=] value of the initializer.
The [=effective-value-type=] of a let-declaration must be either a [=type/concrete=]
[=constructible=] type or a [=pointer type=].

<div class='example wgsl let-declaration at function-scope' heading='let-declared constants at function scope'>
  <xmp highlight=wgsl>
    // 'blockSize' denotes the i32 value 1024.
    let blockSize: i32 = 1024;

    // 'row_size' denotes the u32 value 16u.  The type is inferred.
    let row_size = 16u;
  </xmp>
</div>

## `var` Declarations ## {#var-decls}

A <dfn>variable</dfn> is a named reference to memory that can contain a value
of a particular [=storable=] type.

Two types are associated with a variable: its [=store type=] (the type of value
that may be placed in the referenced memory) and its [=reference type=] (the type
of the variable itself).
If a variable has store type `T`, [=address space=] `AS`, and [=access mode=]
`AM`, then its reference type is `ref<AS,T,AM>`.
The store type of a variable is always [=type/concrete=].

A variable declaration:
* Specifies the variable’s [=name=].
* Determines the variable’s [=address space=], [=store type=], and [=access mode=].
    Together these comprise the variable’s [=reference type=].
    * The store type is the [=effective-value-type=] of the variable’s declaration.
* Ensures the execution environment allocates memory for a value of the store
    type, in the specified address space, supporting the given access mode, for
    the [=lifetime=] of the variable.
* Optionally has an initializer expression if the variable is in the [=address
    spaces/private=] or [=address spaces/function=] address spaces.
    If present, the initializer must evaluate to the variable’s store type.
    If present, the initializer for a [=address spaces/private=] variable must
    be a [=const-expression=] or an [=override-expression=].
    Variables in address spaces other than [=address spaces/function=] or
    [=address spaces/private=] [=shader-creation error|must not=] have an
    initializer.

When an [=identifier=] [=resolves=] to a variable declaration, the identifier
is an expression denoting the reference [=memory view=] for the variable’s memory,
and its type is the variable’s [=reference type=].
See [[#var-identifier-expr]].

If the [=address space=] or [=access mode=] for a variable declaration are specified
in program source, they are written as a [=template list=] after the `var` keyword:
* The [=address space=] is specified first, as one of the [=predeclared=] address space [=enumerants=].
* The [=access mode=] is specified second, if present, as one of the [=predeclared=] address mode [=enumerants=].
    * The address space must be specified if the access mode is specified.

Variables in the [=address spaces/private=], [=address spaces/storage=],
[=address spaces/uniform=], [=address spaces/workgroup=], and [=address
spaces/handle=] address spaces must only be declared in [=module scope=], while
variables in the [=address spaces/function=] address space must only be
declared in [=function scope=].
The address space [=shader-creation error|must=] be specified for all address
spaces except handle and function.
The handle address space [=shader-creation error|must not=] be specified.
Specifying the function address space is optional.

The [=access mode=] always has a default value, and except for variables in the
[=address spaces/storage=] address space, [=shader-creation error|must not=] be
specified in the WGSL source.
See [[#address-space]].

A variable in the [=address spaces/uniform=] address space is a <dfn
noexport>uniform buffer</dfn> variable.
Its [=store type=] must be a [=host-shareable=] [=constructible=] type, and
must satisfy the [[#address-space-layout-constraints|address space layout
constraints]].

A variable in the [=address spaces/storage=] address space is a <dfn
noexport>storage buffer</dfn> variable.
Its [=store type=] must be a [=host-shareable=] type and must satisfy the
[[#address-space-layout-constraints|address space layout constraints]].
The variable may be declared with a [=access/read=] or [=access/read_write=]
access mode; the default is read.

A <dfn>texture resource</dfn> is a variable whose [=effective-value-type=] is a [=texture type=].
It is declared at [=module scope=].
It holds an opaque handle which is used to access the underlying grid of [=texels=] in a [=texture=].
The handle itself is in the [=address spaces/handle=] address space and is always read-only.
In many cases the underlying texels are read-only, and we say the texture variable immutable.
For [=type/write-only storage textures=] and [=type/read-write storage textures=], the underlying texels are mutable, and by convention
we say the texture variable is mutable.

A <dfn>sampler resource</dfn> is a variable whose [=effective-value-type=] is a [=sampler type=].
It is declared at [=module scope=], exists in the [=address spaces/handle=] address space,
and is immutable.

As described in [[#resource-interface]], uniform buffers, storage buffers,
textures, and samplers form the [=resource interface of a shader=].

The <dfn noexport>lifetime</dfn> of a variable is the period during shader
execution for which the [=memory locations=] are associated with the variable.
The lifetime of a [=module scope=] variable is the entire execution of the
shader stage.
There is an independent version of a variable in the [=address spaces/private=]
and [=address spaces/function=] address spaces for each invocation.
[=function scope|Function-scope=] variables are a [=dynamic context=].
The lifetime of a function-scope variable is determined by its scope:
* It starts when control enters the variable’s declaration.
* It ends when the name is no longer [=in scope=] of any part of the [=dynamic context=].
    That is, the lifetime includes any functions [=function call|called=] while
    the name is in scope.

Two [=resource=] variables may have [=overlap|overlapping memory=] locations,
but it is a [=dynamic error=] if either of those variables is mutable.
Other variables with overlapping lifetimes [=behavioral requirement|will=] not
have overlapping memory locations.
When a variable’s lifetime ends, its memory may be used for another variable.

Note: WGSL ensures the contents of a variable are only observable during the
variable’s lifetime.

When a variable in the [=address spaces/private=], [=address spaces/function=],
or [=address spaces/workgroup=] address spaces is created, it [=behavioral
requirement|will=] have an initial value.
If no initializer is specified the initial value is the <dfn noexport>default
initial value</dfn>.
The initial values are computed as follows:
* For variables in the function address space:
    * The [=zero value=] of the [=store type=], if the variable declaration did
        not specify an initializer.
    * Otherwise it is the result of evaluating the
        [=concretization of a value|concretized=] initializer expression at
        that point in program execution.
* For variables in the private address space:
    * The [=zero value=] of the [=store type=], if the variable declaration did
        not specify an initializer.
    * Otherwise it is the result of evaluating the [=concretization of a
        value|concretized=] initializer expression.
        The initializer must be an [=override-expression=], and so its value is
        fixed no later than [=pipeline creation|pipeline-creation time=].
* For variables in the workgroup address space:
    * When the [=store type=] is [=constructible=], the [=zero value=] for the
        store type.
    * If the [=store type=] is an [=atomic type=], the [=zero value=] is that
        of the underlying type ([=type/concrete=] [=integer scalar=]).
    * Otherwise, if the [=store type=] is not [=constructible=], the [=zero
        value=] is determined by recursively applying these rules to each
        [=component=] of the [=composite=] until a [=constructible=] type is
        encountered.
        * Note: This commonly occurs when using an [=array=] with a
            [=pipeline-overridable=] [=element count=] or a [=composite=] that
            contains an [=atomic type=].

Variables in other address spaces are [=resources=] set by bindings in the
[=draw command=] or [=dispatch command=].

Consider the following snippet of WGSL:
<div class='example wgsl function-scope' heading='Variable initial values'>
  <xmp highlight=wgsl>
    var i: i32;         // Initial value is 0.  Not recommended style.
    loop {
      var twice: i32 = 2 * i;   // Re-evaluated each iteration.
      i++;
      if i == 5 { break; }
    }
  </xmp>
</div>
The loop body will execute six times.
Variable `i` will take on values 0, 1, 2, 3, 4, 5, and variable `twice` will take on values 0, 2, 4, 6, and 8.

Consider the following snippet of WGSL:
<div class='example wgsl function-scope' heading='Reading a variable multiple times'>
  <xmp highlight=wgsl>
    var x: f32 = 1.0;
    let y = x * x + x + 1;
  </xmp>
</div>
Because `x` is a variable, all accesses to it turn into load and store operations.
However, it is expected that either the browser or the driver optimizes this intermediate representation
such that the redundant loads are eliminated.

<div class='example wgsl global-scope' heading="Module scope variable declarations">
  <xmp highlight=wgsl>
    var<private> decibels: f32;
    var<workgroup> worklist: array<i32,10>;

    struct Params {
      specular: f32,
      count: i32
    }

    // Uniform buffer. Always read-only, and has more restrictive layout rules.
    @group(0) @binding(2)
    var<uniform> param: Params;    // A uniform buffer

    // A storage buffer, for reading and writing
    @group(0) @binding(0)
    var<storage,read_write> pbuf: array<vec2<f32>>;

    // Textures and samplers are always in "handle" space.
    @group(0) @binding(1)
    var filter_params: sampler;
  </xmp>
</div>

<div class='example wgsl global-scope' heading='Access modes for buffers'>
  <xmp highlight=wgsl>
    // Storage buffers
    @group(0) @binding(0)
    var<storage,read> buf1: Buffer;       // Can read, cannot write.
    @group(0) @binding(0)
    var<storage> buf2: Buffer;            // Can read, cannot write.
    @group(0) @binding(1)
    var<storage,read_write> buf3: Buffer; // Can both read and write.

    struct ParamsTable {weight: f32}

    // Uniform buffer. Always read-only, and has more restrictive layout rules.
    @group(0) @binding(2)
    var<uniform> params: ParamsTable;     // Can read, cannot write.
  </xmp>
</div>

<div class='example wgsl global-scope' heading="Function scope variables and constants">
  <xmp highlight=wgsl>
    fn f() {
       var<function> count: u32;  // A variable in function address space.
       var delta: i32;            // Another variable in the function address space.
       var sum: f32 = 0.0;        // A function address space variable with initializer.
       var pi = 3.14159;          // Infer the f32 store type from the initializer.
    }
  </xmp>
</div>

## Variable and Value Declaration Grammar Summary ## {#var-and-value-decl-grammar}

<pre class=include>
path: syntax/variable_or_value_statement.syntax.bs.include
</pre>
<pre class=include>
path: syntax/variable_decl.syntax.bs.include
</pre>
<pre class=include>
path: syntax/optionally_typed_ident.syntax.bs.include
</pre>
<pre class=include>
path: syntax/global_variable_decl.syntax.bs.include
</pre>
<pre class=include>
path: syntax/global_value_decl.syntax.bs.include
</pre>

# Expressions # {#expressions}

[=Expressions=] specify how values are computed.

The different kinds of value expressions provide a tradeoff between when they
are evaluated and how expressive they can be.
The sooner the evaluation, the more constrained the operations, but also the
more places the value can be used.  This tradeoff leads to different
flexibility with each kind of value declaration.
[=const-expressions=] and [=override-expressions=] are evaluated prior to
execution on the GPU, so only the result of the computation of the expression
is necessary in the final GPU code.
Additionally, because [=const-expressions=] are evaluated at [=shader module
creation|shader-creation time=] they can be used in more situations than
[=override-expressions=], for example, to size [=arrays=] in [=function scope=]
[=variable declaration|variables=].
A <dfn noexport>runtime expression</dfn> is an expression that is neither a
[=const-expression=] nor an [=override-expression=].
A runtime expression is computed on the GPU during shader execution.
While runtime expressions can be used by fewer grammar elements, they can be
computed from a larger class of expressions, for example, other runtime values.

## Early Evaluation Expressions ## {#early-eval-exprs}

WGSL defines two types of expressions that can be evaluated before runtime:
* [=const-expressions=], at [=shader module creation|shader-creation time=]
* [=override-expressions=], at [=pipeline creation|pipeline-creation time=]

### `const` Expressions ### {#const-expr}

Expressions that can be evaluated at [=shader module creation|shader-creation
time=] are called <dfn noexport>const-expressions</dfn>.
An expression is a const-expression if all its [=identifiers=] [=resolve=] to:
* [=const-declarations=], or
* [=const-functions=], or
* [=type aliases=], or
* [=structure=] names.

The type of a `const` expression [=shader-creation error|must=] [=type rules|resolve=] to a type with a
[=creation-fixed footprint=].

Note: [=type/abstract|Abstract types=] can be the inferred type of a const-expression.

A const-expression |E| [=behavioral requirement|will=] be evaluated if and only if:
* |E| is [=top-level expression=], 
* |E| is a [=subexpression=] of an expression |OuterE|, and |OuterE|
    [=behavioral requirement|will=] be evaluated, and evaluation of |OuterE|
    requires |E| to be evaluated,
* |E| is a [=subexpression=] of an expression |OuterE| such that evaluation of
    |E| is required to determine the [=static type=] of |OuterE|, or
* |E| is a [=subexpression=] of an expression |OuterE| such that |OuterE| requires
    |E| to be evaluated to produce a [=shader-creation error=]
    (e.g. [[#arithmetic-expr|integer division]]).

Note: The evaluation rule implies that short-circuiting operators `&&` and `||` guard evaluation of their right-hand
side subexpressions unless there is a [=subexpression=] that requires evaluation to determine
a [=static type=].

A const-expression may be evaluated by the CPU implementing the WebGPU API methods.
Therefore accuracy requirements for operations on [=AbstractFloat=] values are *no more strict* than
required for common WebGPU runtime environments, such as WebAssembly [[WASM-CORE-2]] and ECMAScript [[ECMASCRIPT]].
Accuracy requirements for [=type/concrete=] floating point types (such as f32) are specified in [[#concrete-float-accuracy]].

Example:  `(42)` is analyzed as follows:
* The term `42` is the [=AbstractInt=] value 42.
* Surrounding that term with parentheses produces a new expression `(42)` that is
    of type [=AbstractInt=] with value 42.

Example:  `-5` is analyzed as follows:
* The term `5` is the [=AbstractInt=] value 5.
* Preceding that term with '`-`' produces a new expression `-5` that is
    of type [=AbstractInt=] with value -5.

Example:  `-2147483648` is analyzed as follows:
* The term `2147483648` is the [=AbstractInt=] value 2147483648.
    Note that this value does **not** fit in a 32-bit signed integer.
* Preceding that term with '`-`' produces a new expression `-2147483648` that is
    of type [=AbstractInt=] with value -2147483648.

Example:  `const minint = -2147483648;` is analyzed as follows:
* As above, `-2147483648` evaluates to a [=AbstractInt=] value -2147483648.
* A [=const-declaration=] allows the initializer to be an [=abstract numeric type=].
* The result is that `minint` is declared to be the [=AbstractInt=] value -2147483648.

Example:  `let minint = -2147483648;` is analyzed as follows:
* As above, `-2147483648` evaluates to a [=AbstractInt=] value -2147483648.
* A [=let-declaration=] requires the initializer to be a [=type/concrete=] [=constructible=] type or a pointer type.
* The let-declaration does not have an explicit type, so [=overload resolution=] is used.
    The overload candidates that apply use [=feasible automatic conversions=] from [=AbstractInt=] to either [=i32=], [=u32=], or [=f32=].
    The one of lowest rank is to [=i32=], and so
    [=AbstractInt=] -2147483648 value is converted to the [=i32=] value -2147483648.
* The result is that `minint` is declared to be the i32 value -2147483648.

Example:  `false && (10i < i32(5 * 1000 * 1000 * 1000))` is analyzed as follows:
* The entire expression is a const-expression.
* However, the short-circuiting rules of the `&&` operator apply:
    the left-hand side evaluates to `false`, and so the right-hand side is *not evaluated*.
* Evaluation of i32(5 * 1000 * 1000 * 1000) would have caused a [=shader-creation error=]
    because the [=AbstractInt=] value 5000000000 overflows the [=i32=] type.

Example: `false && array<u32, 1 + 2>(0, 1, 2)[0] == 0`
* The entire expression is a const-expression.
* Type checking requires the `e1 : bool && e2 : bool`:
    * `false` is a bool value.
    * Type checking proceeds on the right-hand side and eventually evaluates `1 + 2`
        in the array element count expression.
* `1 + 2` evaluates to an i32 value of `3`.
    * The array is typed `array<u32, 3i>`.
* Neither the array access expression nor the equality operator are evaluated.

### `override` Expressions ### {#override-expr}

Expressions that can be evaluated at [=pipeline creation=] time are called <dfn
noexport>override-expressions</dfn>.
An expression is an override-expression if all its [=identifiers=] [=resolve=] to:
* [=override-declarations=], or
* [=const-declarations=], or
* [=const-functions=], or
* [=type aliases=], or
* [=structure=] names.

Note: All [=const-expressions=] are also override-expressions.

Override-expressions are only validated or evaluated after any API-provided
values are substituted for [=override-declarations=].
If an [=override-declaration=] has its value substituted via the API, its
initializer expression, if present, will not be evaluated.
Otherwise, an override-expression |E| [=behavioral requirement|will=] be
evaluated if and only if:
* |E| is [=top-level expression=] (after value substitution),
* |E| is a [=subexpression=] of an expression |OuterE|, and |OuterE|
    [=behavioral requirement|will=] be evaluated, and evaluation of |OuterE|
    requires |E| to be evaluated, or
* |E| is a [=subexpression=] of an expression |OuterE| such that |OuterE| requires
    |E| to be evaluated to produce a [=pipeline-creation error=]
    (e.g. [[#arithmetic-expr|integer division]]).

Note: Not all override-expressions may be usable as the initializer for an
[=override-declaration=], because such initializers must [=type rules|resolve=]
to a [=type/concrete=] [=scalar=] type.

Example: `override x = 42;` is analyzed as follows:
* The term `42` is the [=AbstractInt=] value 42.
* An [=override-declaration=] requires a [=type/concrete=] [=scalar=] type.
* `42` is converted to [=i32=] via a [=feasible automatic conversion=].

Example: `let y = x + 1;` is analyzed as follows:
* From above, `x` has a type of [=i32=].
* The expression `x + 1` is an override-expression because it is composed of an
    [=override-declaration=] and an [=integer literal=].
* The expression has a type of [=i32=] and is evaluated at [=pipeline
    creation=] time.
    Its value depends on whether or not `x` is overridden at pipeline creation
    time.

Example: `vec3(x,x,x)` is analyzed as follows:
* From above, `x` is an [=override-declaration=] with the type [=i32=].
* `vec3(x,x,x)` is an override-expression because the only identifiers
    [=resolve=] to override-declarations.
* The type of the expression is a [=vector=] of 3 components
    of [=i32=] (`vec3<i32>`).

<div class='example override-expression errors' heading='Shader-creation errors from override-expressions'>
  <xmp highlight=wgsl>
  override a : i32 = 0;
  override b = a / 0; // shader-creation error,
                      // regardless of attempting to override c
  </xmp>
</div>

<div class='example override-expression errors' heading='Pipeline-creation errors from override-expressions'>
  <xmp highlight=wgsl>
  override a : i32 = 0;
  override b = 1 / a;

  // b is a part of the frag1 shader. When compiling frag1 into a pipeline
  // the following cases may occur:
  // * if b is overridden, no error occurs.
  // * if a is overridden to a non-zero value, no error occurs.
  // * if a is 0 and b is not overridden, a pipeline-creation error occurs.
  @fragment
  fn frag1() {
    _ = b;
  }

  // b is not part of the frag2 shader. When compiling frag2 into a pipeline
  // no errors occur even if b is not overridden and the value of a is 0.
  @fragment
  fn frag2() {
  }
  </xmp>
</div>

## Indeterminate values ## {#indeterminate-values}

In limited cases, an evaluation of a [=runtime expression=] can occur
using unsupported values for its [=subexpressions=].

In such a case, the result of that evaluation is
an <dfn>indeterminate value</dfn> of the expression's [=static type=],
meaning some arbitrary implementation-chosen value of the static type.

A distinct value may be produced for each unique [=dynamic context=] in which the expression is evaluated.
For example, if the evaluation occurs once per iteration of a loop, a distinct
value may be computed for each loop iteration.

Note: If the type is a floating point type and the implementation supports NaN values, then
the indeterminate value produced at runtime may be a NaN value.

<div class='example wgsl global-scope' heading="Indeterminate value example">
  <xmp highlight=wgsl>
    fn fun() {
       var extracted_values: array<i32,2>;
       const v = vec2<i32>(0,1);

       for (var i: i32 = 0; i < 2 ; i++) {
          // A runtime-expression used to index a vector, but outside the
          // indexing bounds of the vector, produces an indeterminate value
          // of the vector component type.
          let extract = v[i+5];

          // Now 'extract' is any value of type i32.

          // Save it for later.
          extracted_values[i] = extract;

          if extract == extract {
             // This is always executed
          }
          if extract < 2 {
             // This might be executed, but might not be executed.
             // Even though the original vector components are 0 and 1,
             // the extracted value might not be either of those values.
          }
       }
       if extracted_values[0] == extracted_values[1] {
          // This might be executed, but might not be executed.
       }
    }

    fn float_fun(runtime_index: u32) {
       const v = vec2<f32>(0,1); // A vector of floating point values

       // As in the previous example, 'float_extract' is an indeterminate value.
       // Since it is a floating point type, it may be a NaN.
       let float_extract: f32 = v[runtime_index+5];

       if float_extract == float_extract {
          // This *might not* be executed, because:
          //  -  'float_extract' may be NaN, and
          //  -  a NaN is never equal to any other floating point number,
          //     even another NaN.
       }
    }
  </xmp>
</div>


## Literal Value Expressions ## {#literal-expressions}

<table class='data'>
  <caption>Scalar literal type rules</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr><td>
      <td>`true`: bool
      <td>`true` boolean value.
  <tr><td>
      <td>`false`: bool
      <td>`false` boolean value.
  <tr><td>|e| is an [=integer literal=] with no suffix
      <td>|e|: AbstractInt
      <td>Abstract integer literal value.
  <tr><td>|e| is a [=floating point literal=] with no suffix
      <td>|e|: AbstractFloat
      <td>Abstract float literal value.
  <tr><td>|e| is an [=integer literal=] with `i` suffix
      <td>|e|: i32
      <td>32-bit signed integer literal value.
  <tr><td>|e| is an [=integer literal=] with `u` suffix
      <td>|e|: u32
      <td>32-bit unsigned integer literal value.
  <tr><td>|e| is an [=floating point literal=] with `f` suffix
      <td>|e|: f32
      <td>32-bit floating point literal value.
  <tr><td>|e| is an [=floating point literal=] with `h` suffix
      <td>|e|: f16
      <td>16-bit floating point literal value.
</table>

## Parenthesized Expressions ## {#parenthesized-expressions}

<table class='data'>
  <caption>Parenthesized expression type rules</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="parenthesized expression">
      <td>|e| : |T|
      <td>`(` |e| `)` : |T|
      <td>Evaluates to |e|.<br>
          Use parentheses to isolate an expression from the surrounding text.
</table>

## Composite Value Decomposition Expressions ## {#composite-value-decomposition-expr}

This section describes expressions for getting a [=component=] of a [=composite=] value,
and for getting a [=reference type|reference=] to a [=component=] from a [=memory view=] to the containing composite value.
For this discussion, the composite value, or the memory view to the composite value,
is known as the <dfn dfn-for=decomposition noexport>base</dfn>.

There are two ways of doing so:
: <dfn noexport>named component expression</dfn>
:: The expression for the [=decomposition/base=] *B* is followed by a period `'.'` (U+002D), and then the name of the component.
    * This is supported when *B* is of [=vector=] or [=structure=] type, or a memory view to a vector or structure type.
    * The valid names depend on *B*'s type.
: <dfn noexport>indexing expression</dfn>
:: The expression for the base is followed by `'['` (U+005B), then the expression for an index then `']'` (U+005D).
    * The base may be a [=vector=], [=matrix=], or [=fixed-size array=] type, or
        or a memory view to a vector, matrix, fixed-size array, or [=runtime-sized=] array type.
    * The index expression [=shader-creation error|must=] be of [=integer scalar=] type.

Syntactically, these two forms are embodied by uses of the [=syntax/component_or_swizzle_specifier=] grammar rule.

<div algorithm="out of bounds index">
The index value |i| of an [=indexing expression=] is an <dfn noexport>in-bounds index</dfn> if 0 &le; |i| &lt; |N|, where |N| is the number of components (elements) of the composite type:
    * |N| is the number of components of the [=vector=] type, when the base is a vector or a [=memory view=] to a vector.
    * |N| is the number of columns of the [=matrix=] type, when the base is a matrix or a memory view to a matrix.
    * |N| is the [=element count=] of the [=fixed-size array=] type, when the base is a fixed-size array or a memory view to a fixed-size array.
    * |N| is [=NRuntime=] for the base, when the base is a memory view to a [=runtime-sized=] array.

The index value is an <dfn noexport>out-of-bounds index</dfn> when it is not an [=in-bounds index=].
An out-of-bounds index is often a programming defect, and will often cause a [[#errors|error]].
See below for details.
</div>

Additionally, vector types support a [=swizzle|swizzling=] syntax for creating a new vector value from the components of another vector.

### Vector Access Expression ### {#vector-access-expr}

Accessing components of a vector can be done either:
* Using array subscripting (e.g. `v[2]`), or
* Using a <dfn noexport>swizzle</dfn> name, a [=context-dependent name=] written as a sequence of convenience names, each mapping to a component of the source vector.
    * The color set of convenience names: `r`, `g`, `b`, `a` for vector components 0, 1, 2, and 3 respectively.
    * The dimensional set of convenience names: `x`, `y`, `z`, `w` for vector components 0, 1, 2, and 3, respectively.

The convenience names are accessed using the `.` notation. (e.g. `color.bgra`).

The convenience letterings [=shader-creation error|must not=] be mixed. For example, you cannot use `.rybw`.

A convenience letter [=shader-creation error|must not=] access a component past the end of the vector.

The convenience letterings can be applied in any order, including duplicating letters as needed.
The provided number of letters [=shader-creation error|must=] be between 1 and 4.
That is, using convenience letters can only produce a scalar type or a valid vector type.

The result type depends on the number of letters provided. Assuming a `vec4<f32>`
<table>
  <thead>
    <tr><th>Accessor<th>Result type
  </thead>
  <tr><td>r<td>`f32`
  <tr><td>rg<td>`vec2<f32>`
  <tr><td>rgb<td>`vec3<f32>`
  <tr><td>rgba<td>`vec4<f32>`
</table>

<div class='example wgsl function-scope'>
  <xmp highlight=wgsl>
    var a: vec3<f32> = vec3<f32>(1., 2., 3.);
    var b: f32 = a.y;          // b = 2.0
    var c: vec2<f32> = a.bb;   // c = (3.0, 3.0)
    var d: vec3<f32> = a.zyx;  // d = (3.0, 2.0, 1.0)
    var e: f32 = a[1];         // e = 2.0
  </xmp>
</div>

#### Vector Single Component Selection #### {#vector-single-component}

<table class='data'>
  <caption>Vector decomposition: single component selection</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="first vector component selection"><td>|e|: vec|N|&lt;|T|&gt;<br>
       <td class="nowrap">
           |e|`.x`: |T|<br>
           |e|`.r`: |T|
       <td>Select the first component of |e|
  <tr algorithm="second vector component selection"><td>|e|: vec|N|&lt;|T|&gt;<br>
       <td class="nowrap">
           |e|`.y`: |T|<br>
           |e|`.g`: |T|
       <td>Select the second component of |e|
  <tr algorithm="third vector component selection"><td>|e|: vec|N|&lt;|T|&gt;<br>
          |N| is 3 or 4
       <td class="nowrap">
           |e|`.z`: |T|<br>
           |e|`.b`: |T|
       <td>Select the third component of |e|
  <tr algorithm="fourth vector component selection"><td>|e|: vec4&lt;|T|&gt;
       <td class="nowrap">
           |e|`.w`: |T|<br>
           |e|`.a`: |T|
       <td>Select the fourth component of |e|

  <tr algorithm="vector indexed component selection concrete">
       <td>|e|: vec|N|&lt;|T|&gt;<br>
           |i|: [INT]<br>
           |T| is [=type/concrete=]
       <td class="nowrap">
           |e|[|i|]: |T|
       <td>Select the |i|'<sup>th</sup> component of vector<br>
           The first component is at index |i|=0.

           If |i| is outside the range [0,|N|-1]:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].
           * Otherwise an [=indeterminate value=] for |T| may be returned.

  <tr algorithm="vector indexed component selection abstract">
       <td>|e|: vec|N|&lt;|T|&gt;<br>
           |i|: [INT]<br>
           |T| is [=type/abstract=]<br>
           |i| is a [=const-expression=]
       <td class="nowrap">
           |e|[|i|]: |T|
       <td>Select the |i|'<sup>th</sup> component of vector<br>
           The first component is at index |i|=0.

           It is a [=shader-creation error=] if |i| is outside the range [0,|N|-1].

           Note: When an abstract vector value |e| is indexed by an expression that
           is not a [=const-expression=], then the vector is
           [=concretization of a value|concretized=] before the index is applied.
</table>

#### Vector Multiple Component Selection #### {#vector-multi-component}

<table class='data'>
  <caption>Vector decomposition: multiple component selection
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="two component vector selection using .x .y">
       <td class="nowrap">
          |e|: vec|N|&lt;|T|&gt; or ptr&lt;|AS|,vec|N|&lt;|T|,|AM|&gt;&gt;<br>
          |I| is the letter `x`, `y`, `z`, or `w`<br>
          |J| is the letter `x`, `y`, `z`, or `w`<br>
          |AM| is `read` or `read_write`<br>
       <td class="nowrap">
           |e|`.`|I||J|: vec2&lt;|T|&gt;<br>
       <td>Computes the two-component vector with first component |e|.|I|, and second component |e|.|J|.<br>
           Letter `z` is valid only when |N| is 3 or 4.<br>
           Letter `w` is valid only when |N| is 4.<br><br>
           If |e| is a pointer, an [=indirection=] is first applied and then the [=load rule=] is invoked.
  <tr algorithm="two component vector selection using .r .g">
       <td class="nowrap">
          |e|: vec|N|&lt;|T|&gt; or ptr&lt;|AS|,vec|N|&lt;|T|,|AM|&gt;&gt;<br>
          |I| is the letter `r`, `g`, `b`, or `a`<br>
          |J| is the letter `r`, `g`, `b`, or `a`<br>
          |AM| is `read` or `read_write`<br>
       <td class="nowrap">
           |e|`.`|I||J|: vec2&lt;|T|&gt;<br>
       <td>Computes the two-component vector with first component |e|.|I|, and second component |e|.|J|.<br>
           Letter `b` is valid only when |N| is 3 or 4.<br>
           Letter `a` is valid only when |N| is 4.<br><br>
           If |e| is a pointer, an [=indirection=] is first applied and then the [=load rule=] is invoked.
  <tr algorithm="three component vector selection using .x .y">
       <td class="nowrap">
          |e|: vec|N|&lt;|T|&gt; or ptr&lt;|AS|,vec|N|&lt;|T|,|AM|&gt;&gt;<br>
          |I| is the letter `x`, `y`, `z`, or `w`<br>
          |J| is the letter `x`, `y`, `z`, or `w`<br>
          |K| is the letter `x`, `y`, `z`, or `w`<br>
          |AM| is `read` or `read_write`<br>
       <td class="nowrap">
           |e|`.`|I||J||K|: vec3&lt;|T|&gt;<br>
       <td>Computes the three-component vector with first component |e|.|I|, second component |e|.|J|, and third component |e|.|K|.<br>
           Letter `z` is valid only when |N| is 3 or 4.<br>
           Letter `w` is valid only when |N| is 4.<br><br>
           If |e| is a pointer, an [=indirection=] is first applied and then the [=load rule=] is invoked.
  <tr algorithm="three component vector selection using .r .g">
       <td class="nowrap">
          |e|: vec|N|&lt;|T|&gt; or ptr&lt;|AS|,vec|N|&lt;|T|,|AM|&gt;&gt;<br>
          |I| is the letter `r`, `g`, `b`, or `a`<br>
          |J| is the letter `r`, `g`, `b`, or `a`<br>
          |K| is the letter `r`, `g`, `b`, or `a`<br>
          |AM| is `read` or `read_write`<br>
       <td class="nowrap">
           |e|`.`|I||J||K|: vec3&lt;|T|&gt;<br>
       <td>Computes the three-component vector with first component |e|.|I|, second component |e|.|J|, and third component |e|.|K|.<br>
           Letter `b` is only valid when |N| is 3 or 4.<br>
           Letter `a` is only valid when |N| is 4.<br><br>
           If |e| is a pointer, an [=indirection=] is first applied and then the [=load rule=] is invoked.
  <tr algorithm="four component vector selection using .x .y">
       <td class="nowrap">
          |e|: vec|N|&lt;|T|&gt; or ptr&lt;|AS|,vec|N|&lt;|T|,|AM|&gt;&gt;<br>
          |I| is the letter `x`, `y`, `z`, or `w`<br>
          |J| is the letter `x`, `y`, `z`, or `w`<br>
          |K| is the letter `x`, `y`, `z`, or `w`<br>
          |L| is the letter `x`, `y`, `z`, or `w`<br>
          |AM| is `read` or `read_write`<br>
       <td class="nowrap">
           |e|`.`|I||J||K||L|: vec4&lt;|T|&gt;<br>
       <td>Computes the four-component vector with first component |e|.|I|, second component |e|.|J|, third component |e|.|K|, and fourth component |e|.|L|.<br>
           Letter `z` is valid only when |N| is 3 or 4.<br>
           Letter `w` is valid only when |N| is 4.<br><br>
           If |e| is a pointer, an [=indirection=] is first applied and then the [=load rule=] is invoked.
  <tr algorithm="four component vector selection using .r .g">
       <td class="nowrap">
          |e|: vec|N|&lt;|T|&gt; or ptr&lt;|AS|,vec|N|&lt;|T|,|AM|&gt;&gt;<br>
          |I| is the letter `r`, `g`, `b`, or `a`<br>
          |J| is the letter `r`, `g`, `b`, or `a`<br>
          |K| is the letter `r`, `g`, `b`, or `a`<br>
          |L| is the letter `r`, `g`, `b`, or `a`<br>
          |AM| is `read` or `read_write`<br>
       <td class="nowrap">
           |e|`.`|I||J||K||L|: vec4&lt;|T|&gt;<br>
       <td>Computes the four-component vector with first component |e|.|I|, second component |e|.|J|, third component |e|.|K|, and fourth component |e|.|L|.<br>
           Letter `b` is only valid when |N| is 3 or 4.<br>
           Letter `a` is only valid when |N| is 4.<br><br>
           If |e| is a pointer, an [=indirection=] is first applied and then the [=load rule=] is invoked.
</table>

Note: In the table above, [=reference types=] are implicitly handled via the [=load rule=].

#### Component Reference from Vector Memory View #### {#component-reference-from-vector-memory-view}

A [=write access=] to component of a vector **may** access all of the [=memory
location|memory locations=] associated with that vector.

Note: This means accesses to different components of a vector by different
invocations must be synchronized if at least one access is a [=write access=].
See [[#sync-builtin-functions]].

<table class='data'>
  <caption>Getting a reference to a component from a memory view to a vector</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="first vector component reference selection">
       <td>|r|: ref&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt; or<br>
           ptr&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt;
       <td class="nowrap">
           |r|`.x`: ref&lt;|AS|,|T|,|AM|&gt;<br>
           |r|`.r`: ref&lt;|AS|,|T|,|AM|&gt;<br>
       <td>Compute a reference to the first component of the vector referenced by the [=memory view=] |r|.<br>
           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
  <tr algorithm="second vector component reference selection">
       <td>|r|: ref&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt; or<br>
           ptr&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt;
       <td class="nowrap">
           |r|`.y`: ref&lt;|AS|,|T|,|AM|&gt;<br>
           |r|`.g`: ref&lt;|AS|,|T|,|AM|&gt;<br>
       <td>Compute a reference to the second component of the vector referenced by the [=memory view=] |r|.<br>
           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
  <tr algorithm="third vector component reference selection">
       <td>|r|: ref&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt; or<br>
           ptr&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt;<br>
           |N| is 3 or 4
       <td class="nowrap">
           |r|`.z`: ref&lt;|AS|,|T|,|AM|&gt;<br>
           |r|`.b`: ref&lt;|AS|,|T|,|AM|&gt;<br>
       <td>Compute a reference to the third component of the vector referenced by the [=memory view=] |r|.<br>
           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
  <tr algorithm="fourth vector component reference selection">
       <td>|r|: ref&lt;|AS|,vec4&lt;|T|&gt;,|AM|&gt; or<br>
           ptr&lt;|AS|,vec4&lt;|T|&gt;,|AM|&gt;
       <td class="nowrap">
           |r|`.w`: ref&lt;|AS|,|T|,|AM|&gt;<br>
           |r|`.a`: ref&lt;|AS|,|T|,|AM|&gt;<br>
       <td>Compute a reference to the fourth component of the vector referenced by the [=memory view=] |r|.<br>
           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
  <tr algorithm="vector indexed component reference selection">
       <td>|r|: ref&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt; or<br>
           ptr&lt;|AS|,vec|N|&lt;|T|&gt;,|AM|&gt;<br>
          |i|: [INT]
       <td class="nowrap">
           |r|[|i|] : ref&lt;|AS|,|T|,|AM|&gt;<br>
       <td>Compute a reference to the |i|'<sup>th</sup> component of the vector
           referenced by the [=memory view=] |r|.

           If |i| is outside the range [0,|N|-1]:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].
           * Otherwise, the expression evaluates to an [=invalid memory reference=].

           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
</table>

### Matrix Access Expression ### {#matrix-access-expr}

<table class='data'>
  <caption>Column vector extraction</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="matrix indexed column vector selection concrete">
       <td class="nowrap">
          |e|: mat|C|x|R|&lt;|T|&gt;<br>
          |i|: [INT]<br>
          |T| is [=type/concrete=]
       <td class="nowrap">
           |e|[|i|]: vec|R|&lt;|T|&gt;
       <td>The result is the |i|'<sup>th</sup> column vector of |e|.

           If |i| is outside the range [0,|C|-1]:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].
           * Otherwise, an [=indeterminate value=] for vec|R|&lt;|T|&gt; may be returned.

  <tr algorithm="matrix indexed column vector selection abstract">
       <td class="nowrap">
          |e|: mat|C|x|R|&lt;|T|&gt;<br>
          |i|: [INT]<br>
          |T| is [=type/abstract=]<br>
          |i| is a [=const-expression=]
       <td class="nowrap">
           |e|[|i|]: vec|R|&lt;|T|&gt;
       <td>The result is the |i|'<sup>th</sup> column vector of |e|.

           It is a [=shader-creation error=] if |i| is outside the range [0,|C|-1].

           Note: When an abstract matrix value |e| is indexed by an expression that
           is not a [=const-expression=], then the matrix is
           [=concretization of a value|concretized=] before the index is applied.
</table>

<table class='data'>
  <caption>Getting a reference to a column vector from a memory view to a matrix</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="matrix indexed column vector reference selection">
       <td class="nowrap">
          |r|: ref&lt;|AS|,mat|C|x|R|&lt;|T|&gt;,|AM|&gt; or<br>
          ptr&lt;|AS|,mat|C|x|R|&lt;|T|&gt;,|AM|&gt;<br>
          |i|: [INT]
       <td class="nowrap">
           |r|[|i|] : ref&lt;|AS|,vec|R|&lt;|T|&gt;,|AM|&gt;
       <td>Compute a reference to the |i|'<sup>th</sup> column vector of the
           matrix referenced by the [=memory view=] |r|.

           If |i| is outside the range [0,|C|-1]:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].
           * Otherwise, the expression evaluates to an [=invalid memory reference=].

           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
</table>

### Array Access Expression ### {#array-access-expr}

<table class='data'>
  <caption>Array element extraction</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="fixed-size array indexed element selection concrete">
       <td class="nowrap">
          |e|: array&lt;|T|,|N|&gt;<br>
          |i|: [INT]<br>
          |T| is [=type/concrete=]
       <td class="nowrap">
           |e|[|i|] : |T|
       <td>The result is the value of the |i|'<sup>th</sup> element of the array value |e|.

           If |i| is outside the range [0,|N|-1]:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].
           * Otherwise, an [=indeterminate value=] for |T| may be returned.
  <tr algorithm="fixed-size array indexed element selection abstract">
       <td class="nowrap">
          |e|: array&lt;|T|,|N|&gt;<br>
          |i|: [INT]<br>
          |T| is [=type/abstract=]<br>
          |i| is a [=const-expression=]
       <td class="nowrap">
           |e|[|i|] : |T|
       <td>The result is the value of the |i|'<sup>th</sup> element of the array value |e|.

           It is a [=shader-creation error=] if |i| is outside the range [0,|N|-1].

           Note: When an abstract array value |e| is indexed by an expression that
           is not a [=const-expression=], then the array is
           [=concretization of a value|concretized=] before the index is applied.
</table>

<table class='data'>
  <caption>Getting a reference to an array element from a memory view to an array</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="fixed-size array indexed reference selection">
       <td class="nowrap">
          |r|: ref&lt;|AS|,array&lt;|T|,|N|&gt;,|AM|&gt; or<br>
          ptr&lt;|AS|,array&lt;|T|,|N|&gt;,|AM|&gt;<br>
          |i|: [INT]
       <td class="nowrap">
           |r|[|i|] : ref&lt;|AS|,|T|,|AM|&gt;
       <td>Compute a reference to the |i|'<sup>th</sup> element of the array
           referenced by the [=memory view=] |r|.

           If |i| is outside the range [0,|N|-1]:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].
           * Otherwise, the expression evaluates to an [=invalid memory reference=].

           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
  <tr algorithm="array indexed reference selection">
       <td>|r|: ref&lt;|AS|,array&lt;|T|&gt;,|AM|&gt; or<br>
          ptr&lt;|AS|,array&lt;|T|&gt;,|AM|&gt;<br>
          |i|: [INT]
       <td class="nowrap">
           |r|[|i|] : ref&lt;|AS|,|T|,|AM|&gt;
       <td>Compute a reference to the |i|'<sup>th</sup> element of the
           runtime-sized array referenced by the [=memory view=] |r|.

           If at runtime the array has |N| elements, and |i| is outside the range
           [0,|N|-1], then the expression evaluates to an [=invalid memory
           reference=].

           If |i| is a signed integer, and |i| is less than 0:<br>
           * It is a [=shader-creation error=] if |i| is a [=const-expression=].
           * It is a [=pipeline-creation error=] if |i| is an [=override-expression=].

           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
</table>


### Structure Access Expression ### {#struct-access-expr}

<table class='data'>
  <caption>Structure member extraction</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="structure member extraction">
       <td class="nowrap">
          |S| is a structure type<br>
          |M| is the identifier name of a member of |S|, having type |T|<br>
          |e|: |S|<br>
       <td class="nowrap">
           |e|.|M|: |T|
       <td>The result is the value of the member with name |M| from the structure value |e|.
</table>

<table class='data'>
  <caption>Getting a reference to a structure member from a memory view to a structure</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="structure member reference selection">
       <td class="nowrap">
          |S| is a structure type<br>
          |M| is the identifier name of a member of |S|, having type |T|<br>
          |r|: ref&lt;|AS|,|S|,|AM|&gt; or<br>
          ptr&lt;|AS|,|S|,|AM|&gt;
       <td class="nowrap">
           |r|.|M|: ref&lt;|AS|,|T|,|AM|&gt;
       <td>Given a memory view to a structure, the result is a reference to the structure member with identifier name |M|.<br>
           The [=originating variable=] of the resulting reference is
           the same as the originating variable of |r|.
</table>

## Logical Expressions ## {#logical-expr}
<table class='data'>
  <caption>Unary logical operations</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="boolean negation"><td>|e|: T<br>|T| is bool or vec|N|&lt;bool&gt;
  <td>`!`|e|: |T|
  <td>Logical negation.
  The result is `true` when |e| is `false` and `false` when |e| is `true`.
  [=Component-wise=] when |T| is a vector.
</table>

<table class='data'>
  <caption>Binary logical expressions</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="short-circuiting or"><td>|e1|: bool<br>|e2|: bool<td>|e1| `||` |e2|`: bool`
  <td>Short-circuiting "or". Yields `true` if either |e1| or |e2| are true;
  evaluates |e2| only if |e1| is false.

  <tr algorithm="short-circuiting and"><td>|e1|: bool<br>|e2|: bool
  <td>|e1| `&&` |e2|`: bool`
  <td>Short-circuiting "and". Yields `true` if both |e1| and |e2| are true;
  evaluates |e2| only if |e1| is true.

  <tr algorithm="logical or"><td>|e1|: |T|<br>|e2|: |T|<br>|T| is bool or vec|N|&lt;bool&gt;
  <td>|e1| `|` |e2|`:` |T|
  <td>Logical "or". [=Component-wise=] when |T| is a vector. Evaluates both |e1| and |e2|.

  <tr algorithm="logical and"><td>|e1|: |T|<br>|e2|: |T|<br>|T| is bool or vec|N|&lt;bool&gt;
  <td>|e1| `&` |e2|`:` |T|
  <td>Logical "and". [=Component-wise=] when |T| is a vector. Evaluates both |e1| and |e2|.
</table>


## Arithmetic Expressions ## {#arithmetic-expr}

<table class='data'>
  <caption>Unary arithmetic expressions</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="negation"><td>|e|: |T|<br>
  |T| is AbstractInt, AbstractFloat, i32, f32, f16, vec|N|&lt;AbstractInt&gt;,
  vec|N|&lt;AbstractFloat&gt;, vec|N|&lt;i32&gt;, vec|N|&lt;f32&gt;, or vec|N|&lt;f16&gt;
  <td>`-`|e|`:` |T|
  <td>Negation. [=Component-wise=] when |T| is a vector.
  If |T| is an [=integer scalar=] type and |e| evaluates to the largest negative value, then the result is |e|.
</table>

<table class='data'>
  <caption>Binary arithmetic expressions</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>

  <tr algorithm="addition">
    <td>|e1| : |T|<br>|e2| : |T|<br>[ALLNUMERICDECL]
    <td>|e1| `+` |e2| : |T|
    <td>Addition. [=Component-wise=] when |T| is a vector.

  <tr algorithm="subtraction">
    <td>|e1| : |T|<br>|e2| : |T|<br>[ALLNUMERICDECL]
    <td>|e1| `-` |e2| : |T|
    <td>Subtraction [=Component-wise=] when |T| is a vector.

  <tr algorithm="multiplication">
    <td>|e1| : |T|<br>|e2| : |T|<br>[ALLNUMERICDECL]
    <td>|e1| `*` |e2| : |T|
    <td>Multiplication. [=Component-wise=] when |T| is a vector.

  <tr algorithm="division">
    <td>|e1| : |T|<br>|e2| : |T|<br>[ALLNUMERICDECL]
    <td>|e1| `/` |e2| : |T|
    <td>Division. [=Component-wise=] when |T| is a vector.

        If |T| is a signed [=integer scalar=] type, evaluates to:
        * If |e2| is zero:
            * It is a [=shader-creation error=] if |e2| is a [=const-expression=].
            * It is a [=pipeline-creation error=] if |e2| is an [=override-expression=].
            * Otherwise, |e1|.
        * If |e1| is most negative value in |T|, and |e2| is -1:
            * It is a [=shader-creation error=] if |e1| and |e2| are [=const-expressions=].
            * It is a [=pipeline-creation error=] if |e1| and |e2| are [=override-expressions=].
            * Otherwise, |e1|.
        * [=truncate=](|x|) otherwise, where |x| is the
            real-valued quotient |e1|&nbsp;&div;&nbsp;|e2|.

        Note:
        The need to ensure truncation behavior may require an implementation
        to perform more operations than when computing an unsigned division.
        Use unsigned division when both operands are known to have the same sign.

        <!--
               where MINIT = most negative value in |T|
               where Divisor = select(e2, 1, (e2==0) | ((e1 == MININT) & (e2 == -1)))
               result is truncate(e1/Divisor)
        -->

        If |T| is an unsigned [=integer scalar=] type, evaluates to:
        * If |e2| is zero:
            * It is a [=shader-creation error=] if |e2| is a [=const-expression=].
            * It is a [=pipeline-creation error=] if |e2| is an [=override-expression=].
            * Otherwise, |e1|.
        * Otherwise, the integer |q| such that
            |e1|&nbsp;=&nbsp;|q|&nbsp;&times;&nbsp;|e2|&nbsp;+&nbsp;|r|,
            where 0 &le; |r| &lt; |e2|.

  <tr algorithm="Remainder">
    <td>|e1| : |T|<br>|e2| : |T|<br>[ALLNUMERICDECL]
    <td>|e1| `%` |e2| : |T|
    <td>Remainder. [=Component-wise=] when |T| is a vector.

       If |T| is a signed [=integer scalar=] type, evaluates |e1| and |e2| once, and evaluates to:
       * if |e2| is zero:
          * It is a [=shader-creation error=] if |e2| is a [=const-expression=].
          * It is a [=pipeline-creation error=] if |e2| is an [=override-expression=].
          * Otherwise, 0.
       * If |e1| is the most negative value in |T|, and |e2| is -1:
          * It is a [=shader-creation error=] if |e1| and |e2| are [=const-expressions=].
          * It is a [=pipeline-creation error=] if |e1| and |e2| are [=override-expressions=].
          * Otherwise, 0.
       * Otherwise, |e1|&nbsp;-&nbsp;[=truncate=](|e1|&nbsp;&div;&nbsp;|e2|)&nbsp;&times;&nbsp;|e2|
           where the quotient is computed as a real value.

       Note:
       When non-zero, the result has the same sign as |e1|.

       Note:
       The need to ensure consistent behavior may require an implementation
       to perform more operations than when computing an unsigned remainder.

       <!--
              where MINIT = most negative value in |T|
              where Divisor = select(e2, 1, (e2==0) | ((e1 == MININT) & (e2 == -1)))
              result is e1 - truncate(e1/Divisor) * Divisor
       -->

       If |T| is an unsigned [=integer scalar=] type, evaluates to:
       * if |e2| is zero:
          * It is a [=shader-creation error=] if |e2| is a [=const-expression=].
          * It is a [=pipeline-creation error=] if |e2| is an [=override-expression=].
          * Otherwise, 0.
       * Otherwise, the integer |r| such that
           |e1|&nbsp;=&nbsp;|q|&nbsp;&times;&nbsp;|e2|&nbsp;+&nbsp;|r|,
           where |q| is an integer and 0 &le; |r| &lt; |e2|.

       If |T| is a floating point type, the result is equal to:<br> |e1| - |e2| * trunc(|e1| / |e2|)

</table>

<table class='data'>
  <caption>Binary arithmetic expressions with mixed scalar and vector operands</caption>
  <thead>
    <th>Preconditions<th>Conclusions<th>Semantics
  </thead>
  <tr algorithm="vector-scalar arithmetic, any scalar type">
    <td rowspan="10">|S| is one of AbstractInt, AbstractFloat, f32, f16, i32, u32<br>
        |V| is vec|N|&lt;|S|&gt;<br>
        |es|: |S|<br>
        |ev|: |V|
    <td>|ev| `+` |es|: |V|
    <td>|ev| `+` |V|(|es|)
  <tr>
    <td>|es| `+` |ev|: |V|
    <td>|V|(|es|) `+` |ev|
  <tr>
    <td>|ev| `-` |es|: |V|
    <td>|ev| `-` |V|(|es|)
  <tr>
    <td>|es| `-` |ev|: |V|
    <td>|V|(|es|) `-` |ev|
  <tr>
    <td>|ev| `*` |es|: |V|
    <td>|ev| `*` |V|(|es|)
  <tr>
    <td>|es| `*` |ev|: |V|
    <td>|V|(|es|) `*` |ev|
  <tr>
    <td>|ev| `/` |es|: |V|
    <td>|ev| `/` |V|(|es|)
  <tr>
    <td>|es| `/` |ev|: |V|
    <td>|V|(|es|) `/` |ev|
  <tr>
    <td>|ev| `%` |es|: |V|
    <td>|ev| `%` |V|(|es|)
  <tr>
    <td>|es| `%` |ev|: |V|
    <td>|V|(|es|) `%` |ev|
</table>

<table class='data'>
  <caption>Matrix arithmetic</caption>
  <thead>
    <th>Preconditions<th>Conclusions<th>Semantics
  </thead>
  <tr algorithm="matrix addition">
    <td rowspan=2>|e1|, |e2|: mat|C|x|R|&lt;|T|&gt;<br>
        |T| is AbstractFloat, f32, or f16
    <td>|e1| `+` |e2|: mat|C|x|R|&lt;|T|&gt;<br>
    <td>Matrix addition: results are computed [=component-wise=], column |i| of the result is |e1|[i] + |e2|[i]
  <tr algorithm="matrix subtraction">
    <td>|e1| `-` |e2|: mat|C|x|R|&lt;|T|&gt;
    <td>Matrix subtraction: results are computed [=component-wise=], column |i| of the result is |e1|[|i|] - |e2|[|i|]
  <tr algorithm="matrix-scalar multiply">
    <td rowspan=2>|m|: mat|C|x|R|&lt;|T|&gt;<br>
        |s|: |T|<br>
        |T| is AbstractFloat, f32, or f16
    <td>|m| `*` |s|:  mat|C|x|R|&lt;|T|&gt;<br>
    <td>[=Component-wise=] scaling: (|m| `*` |s|)[i][j] is |m|[i][j] `*` |s|
  <tr algorithm="scalar-matrix multiply">
    <td>|s| `*` |m|:  mat|C|x|R|&lt;|T|&gt;<br>
    <td>[=Component-wise=] scaling: (|s| `*` |m|)[i][j] is |m|[i][j] `*` |s|
  <tr algorithm="matrix-column-vector multiply">
    <td>|m|: mat|C|x|R|&lt;|T|&gt;<br>
        |v|: vec|C|&lt;|T|&gt;<br>
        |T| is AbstractFloat, f32, or f16
    <td>|m| `*` |v|:  vec|R|&lt;|T|&gt;<br>
    <td>Linear algebra matrix-column-vector product:
        Component |i| of the result is `dot`(transpose(|m|)[|i|],|v|)
  <tr algorithm="matrix-row-vector multiply">
    <td>
        |m|: mat|C|x|R|&lt;|T|&gt;<br>
        |v|: vec|R|&lt;|T|&gt;<br>
        |T| is AbstractFloat, f32, or f16
    <td>|v| `*` |m|:  vec|C|&lt;|T|&gt;<br>
    <td>Linear algebra row-vector-matrix product:<br>
        [=transpose=](transpose(|m|) `*` transpose(|v|))
  <tr algorithm="matrix-matrix multiply">
    <td>|e1|: mat|K|x|R|&lt;|T|&gt;<br>
        |e2|: mat|C|x|K|&lt;|T|&gt;<br>
        |T| is AbstractFloat, f32, or f16
    <td>|e1| `*` |e2|:  mat|C|x|R|&lt;|T|&gt;<br>
    <td>Linear algebra matrix product.

</table>

## Comparison Expressions ## {#comparison-expr}

<table class='data'>
  <caption>Comparisons</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>

  <tr algorithm="equality">
    <td>|e1|: |T|<br>|e2|: |T|<br>
    |S| is AbstractInt, AbstractFloat, bool, i32, u32, f32, or f16<br>
    |T| is |S| or vec|N|&lt;|S|&gt;<br>
    |TB| is vec|N|&lt;bool&gt; if |T| is a vector,<br>
    otherwise |TB| is bool
    <td class="nowrap">|e1| `==` |e2|`:` |TB|
    <td>Equality. [=Component-wise=] when |T| is a vector.
  <tr algorithm="inequality">
    <td>|e1|: |T|<br>|e2|: |T|<br>
    |S| is AbstractInt, AbstractFloat, bool, i32, u32, f32, or f16<br>
    |T| is |S| or vec|N|&lt;|S|&gt;<br>
    |TB| is vec|N|&lt;bool&gt; if |T| is a vector,<br>
    otherwise |TB| is bool
    <td class="nowrap">|e1| `!=` |e2|`:` |TB|
    <td>Inequality. [=Component-wise=] when |T| is a vector.
  <tr algorithm="less than">
    <td>|e1|: |T|<br>|e2|: |T|<br>[ALLNUMERICDECL]<br>
    |TB| is vec|N|&lt;bool&gt; if |T| is a vector,<br>
    otherwise |TB| is bool
    <td class="nowrap">|e1| `<` |e2|`:` |TB|
    <td>Less than. [=Component-wise=] when |T| is a vector.
  <tr algorithm="less than equal">
    <td>|e1|: |T|<br>|e2|: |T|<br>[ALLNUMERICDECL]<br>
    |TB| is vec|N|&lt;bool&gt; if |T| is a vector,<br>
    otherwise |TB| is bool
    <td class="nowrap">|e1| `<=` |e2|`:` |TB|
    <td>Less than or equal. [=Component-wise=] when |T| is a vector.
  <tr algorithm="greater than">
    <td>|e1|: |T|<br>|e2|: |T|<br>[ALLNUMERICDECL]<br>
    |TB| is vec|N|&lt;bool&gt; if |T| is a vector,<br>
    otherwise |TB| is bool
    <td class="nowrap">|e1| `>` |e2|`:` |TB|
    <td>Greater than. [=Component-wise=] when |T| is a vector.
  <tr algorithm="greater than equal">
    <td>|e1|: |T|<br>|e2|: |T|<br>[ALLNUMERICDECL]<br>
    |TB| is vec|N|&lt;bool&gt; if |T| is a vector,<br>
    otherwise |TB| is bool
    <td class="nowrap">|e1| `>=` |e2|`:` |TB|
    <td>Greater than or equal. [=Component-wise=] when |T| is a vector.

</table>

## Bit Expressions ## {#bit-expr}

<table class='data'>
  <caption>Unary bitwise operations</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="complement">
    <td>|e|: |T|<br>
    [ALLINTEGRALDECL]
    <td class="nowrap">`~`|e| : |T|
    <td>Bitwise complement on |e|.
    Each bit in the result is the opposite of the corresponding bit in |e|.
    [=Component-wise=] when |T| is a vector.
</table>

<table class='data'>
  <caption>Binary bitwise operations</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="bitwise or">
    <td>|e1|: |T|<br>
       |e2|: |T|<br>
       [ALLINTEGRALDECL]
    <td class="nowrap">|e1| `|` |e2|: |T|
    <td>Bitwise-or. [=Component-wise=] when |T| is a vector.
  <tr algorithm="bitwise and">
    <td>|e1|: |T|<br>
       |e2|: |T|<br>
       [ALLINTEGRALDECL]
    <td class="nowrap">|e1| `&` |e2|: |T|
    <td>Bitwise-and. [=Component-wise=] when |T| is a vector.
  <tr algorithm="bitwise exclusive or">
    <td>|e1|: |T|<br>
       |e2|: |T|<br>
       [ALLINTEGRALDECL]
    <td class="nowrap">|e1| `^` |e2|: |T|
    <td>Bitwise-exclusive-or. [=Component-wise=] when |T| is a vector.
</table>


<table class='data'>
  <caption>Bit shift expressions</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>

  <tr algorithm="concrete shift left">
    <td>|e1|: |T|<br>
    |e2|: |TS|<br>
    |S| is [INT]<br>
    |T| is |S| or vec|N|&lt;|S|&gt;<br>
    |TS| is u32 when |T| is |S|, otherwise |TS| is vec|N|&lt;u32&gt;
    <td class="nowrap">|e1| `<<` |e2|: |T|
    <td>Shift left (shifted value is concrete):

        Shift |e1| left, inserting zero bits at the least significant positions,
        and discarding the most significant bits.

        The number of bits to shift is the value of |e2|, modulo the bit width of |e1|.<br>
        If |e2| is greater than or equal to the bit width of |e1|, then:
        * It is a [=shader-creation error=] if |e2| is a [=const-expression=].
        * It is a [=pipeline-creation error=] if |e2| is an [=override-expression=].

        When both |e1| and |e2| are known before [=shader execution start=],
        the result must not overflow:
        * If |T| is a signed integer type,
            and the |e2|+1 most significant bits of |e1| do not have the same bit value, then:
            * It is a [=shader-creation error=] if |e1| and |e2| are [=const-expressions=].
            * It is a [=pipeline-creation error=] if |e1| and |e2| are [=override-expressions=].
        * If |T| is an unsigned integer type, and any of the |e2| most significant bits of |e1| are 1, then:
            * It is a [=shader-creation error=] if |e1| and |e2| are [=const-expressions=].
            * It is a [=pipeline-creation error=] if |e1| and |e2| are [=override-expressions=].

        [=Component-wise=] when |T| is a vector.

  <tr algorithm="abstract shift left">
    <td>|e1|: |T|<br>
    |e2|: |TS|<br>
    |T| is AbstractInt or vec|N|&lt;AbstractInt&gt;<br>
    |TS| is u32 when |T| is AbstractInt, otherwise |TS| is vec|N|&lt;u32&gt;
    <td class="nowrap">|e1| `<<` |e2|: |T|
    <td>Shift left (shifted value abstract):

        Shift |e1| left, inserting zero bits at the least significant positions,
        and discarding the most significant bits.

        The number of bits to shift is the value of |e2|.

        The |e2|+1 most significant bits of |e1| [=shader-creation error|must=] have the same bit value.
        Otherwise overflow would occur.

        Note: This condition means all the discarded bits must be the same as the sign bit of the original value,
        and the same as the sign bit of the final value.

        [=Component-wise=] when |T| is a vector.

  <tr algorithm="concrete shift right">
    <td>|e1|: |T|<br>
    |e2|: |TS|<br>
    |S| is [INT]<br>
    |T| is |S| or vec|N|&lt;|S|&gt;<br>
    |TS| is u32 when |T| is |S|, otherwise |TS| is vec|N|&lt;u32&gt;
    <td class="nowrap">|e1| >> |e2|: |T|
    <td>Shift right (shifted value is concrete).

        Shift |e1| right, discarding the least significant bits.

        If |S| is an unsigned type, insert zero bits at the most significant positions.

        If |S| is a signed type:
        * If |e1| is negative, each inserted bit is 1, and so the result is also negative.
        * Otherwise, each inserted bit is 0.

        The number of bits to shift is the value of |e2|, modulo the bit width of |e1|.

        If |e2| is greater than or equal to the bit width or |e1|, then:
        * It is a [=shader-creation error=] if |e2| is a [=const-expression=].
        * It is a [=pipeline-creation error=] if |e2| is an [=override-expression=].

        [=Component-wise=] when |T| is a vector.

  <tr algorithm="abstract shift right">
    <td>|e1|: |T|<br>
    |e2|: |TS|<br>
    |T| is AbstractInt or vec|N|&lt;AbstractInt&gt;<br>
    |TS| is u32 when |T| is AbstractInt, otherwise |TS| is vec|N|&lt;u32&gt;
    <td class="nowrap">|e1| >> |e2|: |T|
    <td>Shift right (abstract).

        Shift |e1| right, discarding the least significant bits.

        If |e1| is negative, each inserted bit is 1, and so the result is also negative.
        Otherwise, each inserted bit is 0.

        The number of bits to shift is the value of |e2|.

        [=Component-wise=] when |T| is a vector.
</table>

## Function Call Expression ## {#function-call-expr}

A function call expression executes a [=function call=] where the called
function has a [=return type=].
If the called function does not return a value, a function call statement
should be used instead.
See [[#function-call-statement]].

## Variable Identifier Expression ## {#var-identifier-expr}

<table class='data'>
  <caption>Getting a reference from a variable name</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="variable reference">
       <td>
          |v| is an [=identifier=] [=resolves|resolving=] to
          an [=in scope|in-scope=] variable declared in [=address space=] |AS|
          with [=store type=] |T| and [=access mode=] |AM|
       <td class="nowrap">
          |v|: ref&lt;|AS|,|T|,|AM|&gt;
       <td>Result is a reference to the memory for the named variable |v|.
</table>

## Formal Parameter Expression  ## {#formal-parameter-expr}

<table class='data'>
  <caption>Getting the value of an identifier declared as a formal parameter to a function</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="formal parameter value">
       <td>
          |a| is an [=identifier=] [=resolves|resolving=] to
          an [=in scope|in-scope=] formal parameter declaration with type |T|
       <td class="nowrap">
          |a|: |T|
       <td>Result is the value supplied for the corresponding function call operand at the [=call site=]
           invoking this instance of the function.
</table>

## Address-Of Expression  ## {#address-of-expr}

The <dfn noexport>address-of</dfn> operator converts a reference to its corresponding pointer.

<table class='data'>
  <caption>Getting a pointer from a reference</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="address-of expression">
       <td>
          |r|: ref&lt;|AS|,|T|,|AM|&gt;
       <td class="nowrap">
          `&`|r|: ptr&lt;|AS|,|T|,|AM|&gt;
       <td>Result is the pointer value corresponding to the
           same [=memory view=] as the reference value |r|.

           If |r| is an [=invalid memory reference=], then the resulting
           pointer is also an invalid memory reference.

           It is a [=shader-creation error=] if |AS| is the [=address spaces/handle=] address space.

           It is a [=shader-creation error=] if |r| is a
           [[#component-reference-from-vector-memory-view|reference to a vector component]].

</table>

## Indirection Expression  ## {#indirection-expr}

The <dfn noexport>indirection</dfn> operator converts a pointer to its corresponding reference.

<table class='data'>
  <caption>Getting a reference from a pointer</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="indirection expression">
       <td>
          |p|: ptr&lt;|AS|,|T|,|AM|&gt;
       <td class="nowrap">
          `*`|p|: ref&lt;|AS|,|T|,|AM|&gt;
       <td>Result is the reference value corresponding to the
           same [=memory view=] as the pointer value |p|.

           If |p| is an [=invalid memory reference=], then the resulting
           reference is also an invalid memory reference.

</table>

## Identifier Expressions for Value Declarations  ## {#value-identifier-expr}

<table class='data'>
  <caption>Getting the value of a `const`-, `override`-, or `let`-declared identifiers</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
  <tr algorithm="const-declared value">
       <td>
          |c| is an [=identifier=] [=resolves|resolving=] to
          an [=in scope|in-scope=] [=const-declaration=] with type |T|
       <td class="nowrap">
          |c|: |T|
       <td>Result is the value computed for the initializer expression.
           The expression is a [=const-expression=], and is evaluated at [=shader module creation|shader-creation=] time.

  <tr algorithm="pipeline-overridable constant value">
       <td>
          |c| is an [=identifier=] [=resolves|resolving=] to
          an [=in scope|in-scope=] [=override-declaration=] with type |T|
       <td class="nowrap">
          |c|: |T|
       <td>If pipeline creation specified a value for the [=pipeline constant ID|constant ID=],
           then the result is that value.
           This value may be different for different pipeline instances.

           Otherwise, the result is the value computed for the initializer expression.
           Pipeline-overridable constants appear at module-scope, so evaluation occurs
           before the shader begins execution.

           Note: Pipeline creation fails if no initial value was specified in the API call
           and the `let`-declaration has no initializer expression.
  <tr algorithm="let-declared value">
       <td>
          |c| is an [=identifier=] [=resolves|resolving=] to
          an [=in scope|in-scope=] [=let-declaration=] with type |T|
       <td class="nowrap">
          |c|: |T|
       <td>Result is the value computed for the initializer expression.
           A [=let-declaration=] appears inside a function body, and its initializer
           is evaluated each time control flow reaches the declaration.<br>
</table>

## Enumeration Expressions ## {#enum-expr}

<table class='data'>
  <caption>Enumeration expressions</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
    <tr algorithm="enumerant expression">
        <td>|e| is an [=identifier=] [=resolves|resolving=] to a [=predeclared=] [=enumerant=]
            belonging to [=enumeration=] type |E|
        <td>|e| : |E|
        <td>See [[#predeclared-enumerants]]
</table>

## Type Expressions ## {#type-expr}

<table class='data'>
  <caption>Type expressions</caption>
  <thead>
    <tr><th>Precondition<th>Conclusion<th>Description
  </thead>
    <tr algorithm="predeclared type expression">
        <td>|t| is an [=identifier=] [=resolves|resolving=] to a [=predeclared=] [=type=]
        <td>|t| : [=AllTypes=]
        <td>See [[#predeclared-types]]
    <tr algorithm="type alias expression">
        <td>|a| is an [=identifier=] [=resolves|resolving=] to a [=type alias=].
        <td>|a| : [=AllTypes=]
        <td>Additionally, |a| denotes the type to which it is aliased.
    <tr algorithm="structure type expression">
        <td>|s| is an [=identifier=] [=resolves|resolving=] to the declaration of a [=structure=] type.
        <td>|s| : [=AllTypes=]
        <td>Additionally, |s| denotes the structure type.
    <tr algorithm="predeclared type generator expression no trailing comma">
        <td rowspan=2>|tg| is an [=identifier=] [=resolves|resolving=] to a [=type-generator=]

            |e1|: |T1|<br>
              ...<br>
            |eN|: <var ignore>TN</var>
        <td>|tg| [=syntax_sym/_template_args_start=]<br>|e1|,<br>...,<br>|eN|<br> [=syntax_sym/_template_args_end=]<br>: [=AllTypes=]
        <td rowspan=2>Each [=type-generator=] has its own requirements on the template parameters it requires and accepts,
            and defines how the template parameters help determine the resulting type.

            The expressions |e1| through |eN| are the [=template parameters=] for the type-generator.

            For example, the type expression `vec2<f32>` is the [=vector=] of two [=f32=] elements.

            See [[#predeclared-types]] for the list of predeclared type-generators.

            Note: The two variants here differ only in whether they have a trailing comma after |eN|.
    <tr algorithm="predeclared type generator expression trailing comma">
        <td><var ignore>tg</var> [=syntax_sym/_template_args_start=]<br>|e1|,<br>...,<br>|eN|,<br> [=syntax_sym/_template_args_end=]<br>: [=AllTypes=]
</table>

## Expression Grammar Summary ## {#expression-grammar}

When an [=identifier=] is the first [=token=] in a [=syntax/call_phrase=], it is one of:
* The name of a [=user-defined function=] or [=built-in function=],
    as part of a [=function call=].
* The name of a [=type=], [[#type-aliases|type alias]], or [=type-generator=],
    as part of a [=value constructor=] expression.

[[#declaration-and-scope|Declaration and scope]] rules ensure those names are always distinct.

<pre class=include>
path: syntax/primary_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/call_expression.syntax.bs.include
</pre>
Note: The [=syntax/call_expression=] rule exists to ensure [=type checking=] applies to the call expression.
<pre class=include>
path: syntax/call_phrase.syntax.bs.include
</pre>

<pre class=include>
path: syntax/paren_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/argument_expression_list.syntax.bs.include
</pre>
<pre class=include>
path: syntax/expression_comma_list.syntax.bs.include
</pre>
<pre class=include>
path: syntax/component_or_swizzle_specifier.syntax.bs.include
</pre>
<pre class=include>
path: syntax/unary_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/singular_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/lhs_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/core_lhs_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/multiplicative_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/multiplicative_operator.syntax.bs.include
</pre>
<pre class=include>
path: syntax/additive_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/additive_operator.syntax.bs.include
</pre>
<pre class=include>
path: syntax/shift_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/relational_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/short_circuit_and_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/short_circuit_or_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/binary_or_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/binary_and_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/binary_xor_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/bitwise_expression.syntax.bs.include
</pre>
<pre class=include>
path: syntax/expression.syntax.bs.include
</pre>

## Operator Precedence and Associativity ## {#operator-precedence-associativity}

This entire subsection is non-normative.

Operator precedence and associativity in [=syntax/expression|right-hand side WGSL expressions=]
emerge from their grammar in summary. Right-hand expressions group operators to organize them,
as illustrated by the following diagram:

<div class=operators1>
  <figure>
    <figcaption>Operator precedence and associativity graph</figcaption>
    <object type="image/svg+xml" data="img/operators_1.mmd.svg"></object>
  </figure>
</div>

To promote readability through verbosity, the following groups do not associate with other groups:

* [=syntax/short_circuit_or_expression|Short-circuit OR=]
    (can associate with [=syntax/short_circuit_or_expression|self=] and [=syntax/relational_expression|relational=] weakly),
* [=syntax/short_circuit_and_expression|Short-circuit AND=]
    (can associate with [=syntax/short_circuit_and_expression|self=] and [=syntax/relational_expression|relational=] weakly),
* [=syntax/binary_or_expression|Binary OR=]
    (can associate with [=syntax/binary_or_expression|self=] and [=syntax/unary_expression|unary=] weakly),
* [=syntax/binary_and_expression|Binary AND=]
    (can associate with [=syntax/binary_and_expression|self=] and [=syntax/unary_expression|unary=] weakly),
* [=syntax/binary_xor_expression|Binary XOR=]
    (can associate with [=syntax/binary_xor_expression|self=] and [=syntax/unary_expression|unary=] weakly).

And the following groups do not associate with themselves:

* [=syntax/shift_expression|Shift=]
    (can associate with [=syntax/unary_expression|unary=] weakly),
* [=syntax/relational_expression|Relational=]
    (can associate with [=syntax/additive_expression|additive=] and [=syntax/shift_expression|shift=] weakly).

Associating both group sections above requires parentheses to set the relationship explicitly.
The following exemplifies where these rules render expressions invalid in comments:

<div class='example wgsl function-scope' heading='Operator precedence corner cases'>
  <xmp highlight=wgsl>
    let a = x & (y ^ (z | w)); // Invalid: x & y ^ z | w
    let b = (x + y) << (z >= w); // Invalid: x + y << z >= w
    let c = x < (y > z); // Invalid: x < y > z
    let d = x && (y || z); // Invalid: x && y || z
  </xmp>
</div>

Emergent precedence controls the implicit parentheses of an expression, where the stronger
binding operator will act as if it is surrounded by parentheses when together with operators
of weaker precedence. For example, stronger binding multiplicative operators than additive will
infer `(a + (b * c))` from `a + b * c` expression. Similarly, the emergent associativity controls
the direction of these implicit parentheses. For example, a left-to-right association will
infer `((a + b) + c)` from `a + b + c` expression, whereas a right-to-left association
will infer `(* (* a))` from `* * a` expression.

The following table summarizes operator precedence, associativity, and binding, sorting
by starting with strongest to weakest. The binding column contains the stronger expression
of the given operator, meaning, for example, if "All above" is the value, then this operator
can include any of the stronger expressions. But, for example, if "Unary" is the value,
then anything weaker than unary but stronger than the operator at row would require parentheses
to bind with this operator. This column is necessary for linearly listing operators.

<table class='data'>
  <caption>
    Operator precedence, associativity, and binding for right-hand side expressions, sorted from strong to weak<br>
  </caption>
  <thead>
    <tr><th>Name
        <th>Operators
        <th>Associativity
        <th>Binding
  </thead>
  <tr><td>[=syntax/paren_expression|Parenthesized=]
      <td>`(...)`
      <td>
      <td>
  <tr><td>[=syntax/primary_expression|Primary=]
      <td>`a()`, `a[]`, `a.b`
      <td>Left-to-right
      <td>
  <tr><td>[=syntax/unary_expression|Unary=]
      <td>`-a`, `!a`, `~a`, `*a`, `&a`
      <td>Right-to-left
      <td>All above
  <tr><td>[=syntax/multiplicative_expression|Multiplicative=]
      <td>`a*b`, `a/b`, `a%b`
      <td>Left-to-right
      <td>All above
  <tr><td>[=syntax/additive_expression|Additive=]
      <td>`a+b`, `a-b`
      <td>Left-to-right
      <td>All above
  <tr><td>[=syntax/shift_expression|Shift=]
      <td>`a<<b`, `a>>b`
      <td>Requires parentheses
      <td>Unary
  <tr><td>[=syntax/relational_expression|Relational=]
      <td>`a<b`, `a>b`, `a<=b`, `a>=b`, `a==b`, `a!=b`
      <td>Requires parentheses
      <td>All above
  <tr><td>[=syntax/binary_and_expression|Binary AND=]
      <td>`a&b`
      <td>Left-to-right
      <td>Unary
  <tr><td>[=syntax/binary_xor_expression|Binary XOR=]
      <td>`a^b`
      <td>Left-to-right
      <td>Unary
  <tr><td>[=syntax/binary_or_expression|Binary OR=]
      <td>`a|b`
      <td>Left-to-right
      <td>Unary
  <tr><td>[=syntax/short_circuit_and_expression|Short-circuit AND=]
      <td>`a&&b`
      <td>Left-to-right
      <td>Relational
  <tr><td>[=syntax/short_circuit_or_expression|Short-circuit OR=]
      <td>`a||b`
      <td>Left-to-right
      <td>Relational
</table>


# Statements # {#statements}

A <dfn>statement</dfn> is a program fragment that controls execution.
Statements are generally executed in sequential order; however,
[[#control-flow|control flow statements]] may cause a program to execute in
non-sequential order.

## Compound Statement ## {#compound-statement-section}

A <dfn>compound statement</dfn> is a brace-enclosed sequence of zero or more statements.
When a [=declaration=] is one of those statements, its [=identifier=] is [=in scope=]
from the start of the next statement until the end of the compound statement.

<pre class=include>
path: syntax/compound_statement.syntax.bs.include
</pre>

The [=syntax/continuing_compound_statement=] is a special form of compound
statement that forms the body of a [[#continuing-statement|continuing]]
statement, and allows an optional [[#break-if-statement|break-if]] statement at
the end.

## Assignment Statement ## {#assignment}

An <dfn noexport dfn-for="statement">assignment</dfn> evaluates an expression,
and optionally stores it in memory (thus updating the contents of a variable).


<pre class=include>
path: syntax/assignment_statement.syntax.bs.include
</pre>


The text to the left of the operator token is the <dfn noexport>left-hand side</dfn>,
and the
expression to the right of the operator token is the <dfn noexport>right-hand side</dfn>.

### Simple Assignment ### {#simple-assignment-section}

An [=statement/assignment=] is a <dfn noexport>simple assignment</dfn> when the
[=left-hand side=] is an expression, and the operator is the equal (<a for=syntax_sym lt=equal>`'='`</a>) token.
In this case the value of the [=right-hand side=] is written to the memory referenced by the left-hand side.

<table class='data'>
  <thead>
    <tr><th style="width:40%">Precondition<th>Statement<th>Description
  </thead>
  <tr algorithm="updating assignment">
    <td>|e|: |T|,<br>
        |T| is a [=type/concrete=] [=constructible=] type,<br>
        |r|: ref<|AS|,|T|,|AM|>,<br>
        |AS| is a writable [=address space=],<br>
        [=access mode=] |AM| is [=access/write=] or [=access/read_write=]<br>
    <td class="nowrap">|r| = |e|
    <td>Evaluates |r|, then evaluates |e|, then writes the value computed for |e| into
        the [=memory locations=] referenced by |r|.

        Note: If the reference is an [=invalid memory reference=], the write
        may not execute, or may write to a different memory location than
        expected.
</table>

In the simplest case, the left hand side is the name of a variable.
See [[#forming-references-and-pointers]] for other cases.

    <div class='example wgsl' heading='Assignments'>
      <xmp highlight=wgsl>
        struct S {
            age: i32,
            weight: f32
        }
        var<private> person: S;

        fn f() {
            var a: i32 = 20;
            a = 30;           // Replace the contents of 'a' with 30.

            person.age = 31;  // Write 31 into the age field of the person variable.

            var uv: vec2<f32>;
            uv.y = 1.25;      // Place 1.25 into the second component of uv.

            let uv_x_ptr: ptr<function,f32> = &uv.x;
            *uv_x_ptr = 2.5;  // Place 2.5 into the first component of uv.

            var sibling: S;
            // Copy the contents of the 'person' variable into the 'sibling' variable.
            sibling = person;
        }
      </xmp>
    </div>

### Phony Assignment ### {#phony-assignment-section}

An [=statement/assignment=] is a <dfn noexport>phony assignment</dfn> when the
[=left-hand side=] is the underscore (<a for=syntax_sym lt=equal>`'_'`</a>) token.
In this case the [=right-hand side=] is evaluated, and then ignored.

<table class='data'>
  <thead>
    <tr><th>Precondition<th>Statement<th>Description
  </thead>
  <tr algorithm="phony-assignment">
    <td>|e|: |T|,<br>
        |T| is [=constructible=], a [=pointer type=], a [=texture=] type, or a [=sampler=] type
    <td class="nowrap">_ = |e|
    <td>Evaluates |e|.

        Note: The resulting value is not stored.
        The `_` token is not an identifier, and therefore cannot be used in an expression.
</table>

A phony-assignment is useful for:
* Calling a function that returns a value, but clearly expressing that the resulting value
    is not needed.
* [=statically accessed|Statically accessing=] a variable, thus establishing it as a part of
    the [=resource interface of a shader|shader's resource interface=].

    Note: A buffer variable's store type may not be constructible, e.g. it contains an atomic type, or a runtime-sized array.
    In these cases, use a pointer to the variable's contents instead.

<div class='example wgsl global-scope' heading='Using phony-assignment to throw away an un-needed function result'>
  <xmp highlight=wgsl>
    var<private> counter: i32;

    fn increment_and_yield_previous() -> i32 {
      let previous = counter;
      counter = counter + 1;
      return previous;
    }

    fn user() {
      // Increment the counter, but don't use the result.
      _ = increment_and_yield_previous();
    }
  </xmp>
</div>


<div class='example wgsl global-scope' heading='Using phony-assignment to occupy bindings without using them'>
  <xmp highlight=wgsl>
    struct BufferContents {
        counter: atomic<u32>,
        data: array<vec4<f32>>
    }
    @group(0) @binding(0) var<storage> buf: BufferContents;
    @group(0) @binding(1) var t: texture_2d<f32>;
    @group(0) @binding(2) var s: sampler;

    @fragment
    fn shade_it() -> @location(0) vec4<f32> {
      // Declare that buf, t, and s are part of the shader interface, without
      // using them for anything.
      _ = &buf;
      _ = t;
      _ = s;
      return vec4<f32>();
    }
  </xmp>
</div>

### Compound Assignment ### {#compound-assignment-sec}

An [=statement/assignment=] is a <dfn noexport>compound assignment</dfn> when the
[=left-hand side=] is an expression, and the operator is one of the [=syntax/compound_assignment_operators=].

<pre class=include>
path: syntax/compound_assignment_operator.syntax.bs.include
</pre>

The type requirements, semantics, and behavior of each statement is defined as if
the compound assignment expands as in the following table, except that:
* the reference expression |e1| is evaluated only once, and
* the [=reference type=] for |e1| [=shader-creation error|must=] have a [=access/read_write=] [=access mode=].

<table class='data'>
  <thead>
    <tr><th>Statement<th>Expansion
  </thead>
<tr algorithm="add-assign">
    <td class="nowrap">|e1| += |e2|
    <td>|e1| = |e1| + (|e2|)
<tr algorithm="subtract-assign">
    <td class="nowrap">|e1| -= |e2|
    <td>|e1| = |e1| - (|e2|)
<tr algorithm="multiply-assign">
    <td class="nowrap">|e1| *= |e2|
    <td>|e1| = |e1| * (|e2|)
<tr algorithm="divide-assign">
    <td class="nowrap">|e1| /= |e2|
    <td>|e1| = |e1| / (|e2|)
<tr algorithm="modulus-assign">
    <td class="nowrap">|e1| %= |e2|
    <td>|e1| = |e1| % (|e2|)
<tr algorithm="bitwise-and-assign">
    <td class="nowrap">|e1| &= |e2|
    <td>|e1| = |e1| & (|e2|)
<tr algorithm="bitwise-or-assign">
    <td class="nowrap">|e1| |= |e2|
    <td>|e1| = |e1| | (|e2|)
<tr algorithm="bitwise-xor-assign">
    <td class="nowrap">|e1| ^= |e2|
    <td>|e1| = |e1| ^ (|e2|)
<tr algorithm="bitwise-shiftright-assign">
    <td class="nowrap">|e1| >>= |e2|
    <td>|e1| = |e1| >> (|e2|)
<tr algorithm="bitwise-shiftleft-assign">
    <td class="nowrap">|e1| <<= |e2|
    <td>|e1| = |e1| << (|e2|)
</table>

Note: The syntax does not allow a [=compound assignment=] to also be a [=phony assignment=].

Note: Even though the reference |e1| is evaluated once, its underlying memory is accessed twice:
first a [=read access=] gets the old value, and then a [=write access=] stores the updated value.

<div class='example wgsl global-scope' heading="Compound assignment">
  <xmp highlight=wgsl>
    var<private> next_item: i32 = 0;

    fn advance_item() -> i32 {
       next_item += 1;   // Adds 1 to next_item.
       return next_item - 1;
    }

    fn bump_item() {
      var data: array<f32,10>;
      next_item = 0;
      // Adds 5.0 to data[0], calling advance_item() only once.
      data[advance_item()] += 5.0;
      // next_item will be 1 here.
    }

    fn precedence_example() {
      var value = 1;
      // The right-hand side of a compound assignment is its own expression.
      value *= 2 + 3; // Same as value = value * (2 + 3);
      // 'value' now holds 5.
    }
  </xmp>
</div>

<div class=note><span class=marker>Note:</span>
A compound assignment can rewritten as different WGSL code that uses a [=simple assignment=] instead.
The idea is to use a pointer to hold the result of evaluating the reference once.

<p algorithm="translation compound assignment not vector component">For example,
when |e1| is *not* a reference to a component inside a vector, then
<blockquote>
|e1|` += `|e2|;
</blockquote>
can be rewritten as
<blockquote>
`{ let p = &(`|e1|`); *p = *p + (`|e2|`); }`
</blockquote>
where the identifier `p` is chosen to be different from all other identifiers in the program.
</p>

<p algorithm="translation compound assignment vector component">When
|e1| is a reference to a component inside a vector, the above technique
needs to be modified because WGSL does not allow [[#address-of-expr|taking the address]] in that case.
For example, if <var ignore>ev</var> is a reference to a vector, the statement
<blockquote>
|ev|`[`|c|`] += ` |e2|;
</blockquote>
can be rewritten as
<blockquote>
`{ let p = &(`|ev|`); let c0 = ` |c|`; (*p)[c0] = (*p)[c0] + (`|e2|`); }`
</blockquote>
where identifiers `c0` and `p` are chosen to be different from all other identifiers in the program.
</div>
</div>

## Increment and Decrement Statements ## {#increment-decrement}

An <dfn noexport>increment statement</dfn> adds 1 to the contents of a variable.
A <dfn noexport>decrement statement</dfn> subtracts 1 from the contents of a variable.

<pre class=include>
path: syntax/increment_statement.syntax.bs.include
</pre>

<pre class=include>
path: syntax/decrement_statement.syntax.bs.include
</pre>

The expression [=shader-creation error|must=] evaluate to a reference with a [=type/concrete=] [=integer scalar=] [=store type=] and [=access/read_write=] [=access mode=].

<table class='data'>
  <thead>
    <tr><th>Precondition<th>Statement<th>Description
  </thead>
  <tr algorithm="increment statement">
    <td class="nowrap">|r| : ref&lt;|AS|,|T|,[=access/read_write=]&gt;,<br>
        |T| is a [=type/concrete=] [=integer scalar=]<br>
    <td class="nowrap">|r|`++`
    <td>Adds 1 to the contents of memory referenced by |r|.
        <br>Same as |r| += |T|(1)
  <tr algorithm="decrement statement">
    <td class="nowrap">|r| : ref&lt;|AS|,|T|,[=access/read_write=]&gt;,<br>
        |T| is a [=type/concrete=] [=integer scalar=]<br>
    <td class="nowrap">|r|`--`
    <td>Subtracts 1 from the contents of memory referenced by |r|.
        <br>Same as |r| -= |T|(1)
</table>

    <div class='example wgsl' heading='Increment and decrement'>
      <xmp highlight=wgsl>
        fn f() {
            var a: i32 = 20;
            a++;
            // Now a contains 21
            a--;
            // Now a contains 20
        }
      </xmp>
    </div>

## Control Flow ## {#control-flow}

Control flow statements may cause the program to execute in non-sequential order.

### If Statement ### {#if-statement}

An <dfn noexport dfn-for="statement">if</dfn> statement conditionally executes at most one [=compound statement=] based on
the evaluation of condition expressions.

An `if` statement has an `if` clause, followed by zero or more `else if` clauses, followed by an optional `else` clause.

<pre class=include>
path: syntax/if_statement.syntax.bs.include
</pre>

<pre class=include>
path: syntax/if_clause.syntax.bs.include
</pre>

<pre class=include>
path: syntax/else_if_clause.syntax.bs.include
</pre>

<pre class=include>
path: syntax/else_clause.syntax.bs.include
</pre>

[=Type rule precondition=]:
The expression in each `if` and `else if` clause [=shader-creation error|must=] be of [=bool=] type.

An `if` statement is executed as follows:
* The condition associated with the `if` clause is evaluated.
    If the result is `true`,
    control transfers to the first compound statement (immediately after the condition expression).
* Otherwise, the condition of the next `else if` clause in textual order (if one exists) is evaluated
     and, if the result is `true`, control transfers to the associated compound statement.
     * This behavior is repeated for all `else if` clauses until one of the conditions evaluates to `true`.
* If no condition evaluates to `true`, then control transfers to the compound statement
    associated with the `else` clause (if it exists).

### Switch Statement ### {#switch-statement}

A <dfn noexport dfn-for="statement">switch</dfn> statement transfers control to one of a set of [=case clauses=], or to the [=default clause=],
depending on the evaluation of a selector expression.

<pre class=include>
path: syntax/switch_statement.syntax.bs.include
</pre>
<pre class=include>
path: syntax/switch_body.syntax.bs.include
</pre>
<pre class=include>
path: syntax/switch_clause.syntax.bs.include
</pre>
<pre class=include>
path: syntax/case_clause.syntax.bs.include
</pre>
<pre class=include>
path: syntax/default_alone_clause.syntax.bs.include
</pre>
<pre class=include>
path: syntax/case_selectors.syntax.bs.include
</pre>
<pre class=include>
path: syntax/case_selector.syntax.bs.include
</pre>

A <dfn noexport>case clause</dfn> is the <a for=syntax_kw lt=case>`'case'`</a> token followed by a comma-separated list of [=syntax/case_selector|case selectors=] and a
body in the form of a [=compound statement=].

A <dfn noexport>default-alone clause</dfn> is the <a for=syntax_kw lt=default>`'default'`</a> token followed by a body in the form of a [=compound statement=].

A <dfn noexport>default clause</dfn> is either:
* a [=case clause=] where <a for=syntax_kw lt=default>`'default'`</a> appears as one of its selectors, or
* a [=default-alone clause=].

Each switch statement [=shader-creation error|must=] have exactly one [=default clause=].

The <a for=syntax_kw lt=default>`'default'`</a> token [=shader-creation error|must=] not appear more than once in a single [=syntax/case_selector=] list.

[=Type rule precondition=]:
For a single switch statement, the selector expression and all case selector expressions [=shader-creation error|must=] be of the same [=type/concrete=] [=integer scalar=] type.

The expressions in the [=syntax/case_selectors=] [=shader-creation error|must=]
be [=const-expressions=].

Two different case selector expressions in the same switch statement [=shader-creation error|must not=] have the same value.

If the selector value equals the value of an expression in a [=syntax/case_selector=] list,
then control is transferred to the body of that [=case clause=].
If the selector value does not equal any of the case selector values, then control is
transferred to the body of the [=default clause=].

When control reaches the end of the body of a clause, control transfers to the first statement after the switch statement.

When one of the statements in the body of a clause is a [=declaration=],
it follows the normal [=scope=] and [=lifetime=] rules of a declaration in a [=compound statement=].
That is, the body is a sequence of statements, and if one of those is a declaration
then the scope of that declaration extends from the start of the next statement in the sequence
until the end of the body.
The declaration executes when it is reached,
creating a new instance of the [=variable declaration|variable=] or [=value declaration|value=], and initializes it.

<div class='example wgsl function-scope' heading='WGSL Switch'>
  <xmp highlight=wgsl>
    var a : i32;
    let x : i32 = generateValue();
    switch x {
      case 0: {      // The colon is optional
        a = 1;
      }
      default {      // The default need not appear last
        a = 2;
      }
      case 1, 2, {   // Multiple selector values can be used
        a = 3;
      }
      case 3, {      // The trailing comma is optional
        a = 4;
      }
      case 4 {
        a = 5;
      }
    }
  </xmp>
</div>

<div class='example wgsl function-scope' heading='WGSL Switch with default combined'>
  <xmp highlight=wgsl>
    const c = 2;
    var a : i32;
    let x : i32 = generateValue();
    switch x {
      case 0: {
        a = 1;
      }
      case 1, c {       // Const-expression can be used in case selectors
        a = 3;
      }
      case 3, default { // The default keyword can be used with other clauses
        a = 4;
      }
    }
  </xmp>
</div>

### Loop Statement ### {#loop-statement}

<pre class=include>
path: syntax/loop_statement.syntax.bs.include
</pre>

A <dfn noexport dfn-for="statement">loop</dfn> statement repeatedly executes a <dfn noexport>loop body</dfn>;
the loop body is specified as a [=compound statement=].
Each execution of the loop body is called an <dfn noexport>iteration</dfn>.

This repetition can be interrupted by a [=statement/break=], or
[=statement/return=] statement.

Optionally, the last statement in the loop body may be a
[=statement/continuing=] statement.

When one of the statements in the loop body is a [=declaration=],
it follows the normal [=scope=] and [=lifetime=] rules of a declaration in a [=compound statement=].
That is, the loop body is a sequence of statements, and if one of those is a declaration
then the scope of that declaration extends from the start of the next statement in the sequence
until the end of the loop body.
The declaration executes each time it is reached, so each new iteration
creates a new instance of the [=variable declaration|variable=] or [=value declaration|value=], and re-initializes it.

Note: The loop statement is one of the biggest differences from other shader
languages.

This design directly expresses loop idioms commonly found in compiled code.
In particular, placing the loop update statements at the end of the loop body
allows them to naturally use values defined in the loop body.

<div class='example glsl' heading='GLSL Loop'>
  <xmp>
    int a = 2;
    for (int i = 0; i < 4; i++) {
      a *= 2;
    }
  </xmp>
</div>

<div class='example wgsl function-scope' heading="WGSL Loop">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    var i: i32 = 0;      // <1>
    loop {
      if i >= 4 { break; }

      a = a * 2;

      i++;
    }
  </xmp>
</div>
* <1> The initialization is listed before the loop.

<div class='example glsl' heading='GLSL Loop with continue'>
  <xmp>
    int a = 2;
    int step = 1;
    for (int i = 0; i < 4; i += step) {
      if (i % 2 == 0) continue;
      a *= 2;
    }
  </xmp>
</div>

<div class='example wgsl function-scope' heading="WGSL Loop with continue">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    var i: i32 = 0;
    loop {
      if i >= 4 { break; }

      let step: i32 = 1;

      i = i + step;
      if i % 2 == 0 { continue; }

      a = a * 2;
    }
  </xmp>
</div>

<div class='example wgsl function-scope' heading="WGSL Loop with continue and continuing">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    var i: i32 = 0;
    loop {
      if i >= 4 { break; }

      let step: i32 = 1;

      if i % 2 == 0 { continue; }

      a = a * 2;

      continuing {   // <2>
        i = i + step;
      }
    }
  </xmp>
</div>
* <2> The continue construct is placed at the end of the `loop`

### For Statement ### {#for-statement}

<pre class=include>
path: syntax/for_statement.syntax.bs.include
</pre>

<pre class=include>
path: syntax/for_header.syntax.bs.include
</pre>

<pre class=include>
path: syntax/for_init.syntax.bs.include
</pre>
<pre class=include>
path: syntax/for_update.syntax.bs.include
</pre>

The <dfn dfn-for="statement">for</dfn> statement takes the form
`for (initializer; condition; update_part) { body }` and is syntactic sugar on top of a [=statement/loop=] statement with the same `body`.
Additionally:
* If `initializer` is non-empty, it is executed inside an additional [=scope=] before the first [=iteration=].
    The scope of a declaration in the initializer extends to the end of the loop body.
* [=Type rule precondition=]: If the condition is non-empty, it [=shader-creation error|must=] be an expression of [=bool=] type.
    * If present, the condition is evaluated immediately before executing the loop body.
        If the condition is false, then a [[#break-statement]] is executed, finishing execution of the loop.
        This check is performed at the start of each loop iteration.
* If `update_part` is non-empty, it becomes a [=statement/continuing=] statement at the end of the loop body.

The `initializer` of a for loop is executed once prior to executing the loop.
When a [=declaration=] appears in the initializer, its [=identifier=] is [=in scope=] until the end of the `body`.
Unlike declarations in the `body`, the declaration is not re-initialized each iteration.

The `condition`, `body` and `update_part` execute in that order to form a loop [=iteration=].
The `body` is a special form of [=compound statement=].
The identifier of a declaration in the `body` is [=in scope=] from the start of
the next statement until the end of the `body`.
The declaration is executed each time it is reached, so each new iteration
creates a new instance of the variable or constant, and re-initializes it.

<div class='example wgsl function-scope' heading="For to Loop transformation: before">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    for (var i: i32 = 0; i < 4; i++) {
      if a == 0 {
        continue;
      }
      a = a + 2;
    }
  </xmp>
</div>

Converts to:

<div class='example wgsl function-scope' heading="For to Loop transformation: after">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    { // Introduce new scope for loop variable i
      var i: i32 = 0;
      loop {
        if !(i < 4) {
          break;
        }

        if a == 0 {
          continue;
        }
        a = a + 2;

        continuing {
          i++;
        }
      }
    }
  </xmp>
</div>

### While Statement ### {#while-statement}

<pre class=include>
path: syntax/while_statement.syntax.bs.include
</pre>

The <dfn noexport dfn-for="statement">while</dfn> statement is a kind of loop parameterized by a condition.
At the start of each loop [=iteration=], a boolean condition is evaluated.
If the condition is false, the while loop ends execution.
Otherwise, the rest of the iteration is executed.

[=Type rule precondition=]: The condition [=shader-creation error|must=] be of [=bool=] type.

A while loop can be viewed as syntactic sugar over either a [=statement/loop=] or [=statement/for=] statement.
The following statement forms are equivalent:
* `while`  *condition*  `{` *body_statements* `}`
* `loop { if !` *condition* `{break;}` *body_statements* `}`
* `for (;`  *condition* `;) {` *body_statements*  `}`

### Break Statement ### {#break-statement}

<pre class=include>
path: syntax/break_statement.syntax.bs.include
</pre>

A <dfn noexport dfn-for="statement">break</dfn> statement transfers control to immediately
after the body of the nearest-enclosing loop
or [=statement/switch=] statement, thus ending execution of the loop or switch statement.

A `break` statement [=shader-creation error|must=] only be used within [=statement/loop=], [=statement/for=], [=statement/while=], and [=statement/switch=] statements.

A `break` statement [=shader-creation error|must not=] be placed such that it would exit from a loop's [[#continuing-statement|continuing]] statement.
Use a [[#break-if-statement|break-if]] statement instead.

<div class='example wgsl function-scope' heading="WGSL Invalid loop break from a continuing clause">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    var i: i32 = 0;
    loop {
      let step: i32 = 1;

      if i % 2 == 0 { continue; }

      a = a * 2;

      continuing {
        i = i + step;
        if i >= 4 { break; } // Invalid.  Use break-if instead.
      }
    }
  </xmp>
</div>

### Break-If Statement ### {#break-if-statement}

<pre class=include>
path: syntax/break_if_statement.syntax.bs.include
</pre>

A <dfn noexport dfn-for="statement">break-if</dfn> statement evaluates a boolean condition;
If the condition is true, control is transferred to immediately after the body of the nearest-enclosing [=statement/loop=]
statement, ending execution of that loop.

[=Type rule precondition=]: The condition [=shader-creation error|must=] be of [=bool=] type.

Note: A break-if statement may only appear as the last statement in the body of a [[#continuing-statement|continuing]]
statement.

<div class='example wgsl function-scope' heading="WGSL Valid loop break-if from a continuing clause">
  <xmp highlight=wgsl>
    var a: i32 = 2;
    var i: i32 = 0;
    loop {
      let step: i32 = 1;

      if i % 2 == 0 { continue; }

      a = a * 2;

      continuing {
        i = i + step;
        break if i >= 4;
      }
    }
  </xmp>
</div>

### Continue Statement ### {#continue-statement}

<pre class=include>
path: syntax/continue_statement.syntax.bs.include
</pre>

A <dfn noexport dfn-for="statement">continue</dfn> statement transfers control in the nearest-enclosing [=statement/loop=]:

*  forward to the [=statement/continuing=] statement at the end of the body of that loop, if it exists.
*  otherwise backward to the first statement in the loop body, starting the next [=iteration=].

A `continue` statement [=shader-creation error|must=] only be used in a [=statement/loop=], [=statement/for=] or [=statement/while=] statement.
A `continue` statement [=shader-creation error|must not=] be placed such that it would transfer
control to an enclosing [=statement/continuing=] statement.
(It is a *forward* branch when branching to a `continuing` statement.)

A `continue` statement [=shader-creation error|must not=] be placed such that it would transfer
control past a declaration used in the targeted [=statement/continuing=] statement.

Note: A `continue` can only be used in a `continuing` statement if it is used for transferring control
flow within another loop nested in the `continuing` statement. That is, a `continue`
cannot be used to transfer control to the start of the currently executing `continuing` statement.

<div class='example wgsl function-scope expect-error' heading="Invalid continue bypasses declaration">
  <xmp highlight=wgsl>
    var i: i32 = 0;
    loop {
      if i >= 4 { break; }
      if i % 2 == 0 { continue; } // <3>

      let step: i32 = 2;

      continuing {
        i = i + step;
      }
    }
  </xmp>
</div>
* <3> The `continue` is invalid because it bypasses the declaration of `step` used in the `continuing` construct

### Continuing Statement ### {#continuing-statement}

<pre class=include>
path: syntax/continuing_statement.syntax.bs.include
</pre>

<pre class=include>
path: syntax/continuing_compound_statement.syntax.bs.include
</pre>

A <dfn dfn-for="statement">continuing</dfn> statement specifies a [=compound statement=] to be executed at the end of a loop [=iteration=].
The construct is optional.

The compound statement [=shader-creation error|must not=] contain a [=statement/return=] at any compound statement nesting level.

### Return Statement ### {#return-statement}

<pre class=include>
path: syntax/return_statement.syntax.bs.include
</pre>

A <dfn noexport dfn-for="statement">return</dfn> statement ends execution of the current function.
If the function is an [=entry point=], then the current shader invocation
is terminated.
Otherwise, evaluation continues with the next expression or statement after
the evaluation of the [=call site=] of the current function invocation.

If the function does not have a [=return type=], then the [=statement/return=] statement is
optional. If the return statement is provided for such a function, it [=shader-creation error|must not=]
supply a value.
Otherwise the expression [=shader-creation error|must=] be present, and is called the <dfn>return value</dfn>.
In this case the call site of this function invocation evaluates to the return value.
The type of the return value [=shader-creation error|must=] match the return type of the function.

### Discard Statement ### {#discard-statement}

A <dfn dfn-for="statement">discard</dfn> statement converts the invocation into
a [=helper invocation=] and throws away the fragment.
The `discard` statement [=shader-creation error|must=] only be used in a [=fragment=] shader stage.

More precisely, executing a `discard` statement [=behavioral requirement|will=]:

* convert the current invocation into a [=helper invocation=], and
* prevent the current fragment from being processed downstream in the [=GPURenderPipeline=].

Only statements executed prior to the `discard` statement [=behavioral
requirement|will=] have observable effects.

Note: A `discard` statement may be executed by any
[=functions in a shader stage|function in a fragment stage=] and the effect is the same:
the fragment will be thrown away.

<div class='example wgsl' heading='Using the discard statement to throw away a fragment'>
  <xmp highlight=wgsl>
  @group(0) @binding(0)
  var<storage, read_write> will_emit_color : u32;

  fn discard_if_shallow(pos: vec4<f32>) {
    if pos.z < 0.001 {
      // If this is executed, then the will_emit_color variable will
      // never be set to 1 because helper invocations will not write
      // to shared memory.
      discard;
    }
    will_emit_color = 1;
  }

  @fragment
  fn main(@builtin(position) coord_in: vec4<f32>)
    -> @location(0) vec4<f32>
  {
    discard_if_shallow(coord_in);

    // Set the value to 1 and emit red, but only if the helper function
    // did not execute the discard statement.
    will_emit_color = 1;
    return vec4<f32>(1.0, 0.0, 0.0, 1.0);
  }
  </xmp>
</div>

## Function Call Statement ## {#function-call-statement}

<pre class=include>
path: syntax/func_call_statement.syntax.bs.include
</pre>

A function call statement executes a [=function call=].

A [=shader-creation error=] results if the called function has the [=attribute/must_use=] attribute.

Note: If the function [=return value|returns a value=],
and the function does not have the [=attribute/must_use=] attribute,
that value is ignored.

## Const Assertion Statement ## {#const-assert-statement}

A const assertion statement produces a [=shader-creation error=] if the
expression evaluates to `false`.
The expression [=shader-creation error|must=] be a [=const-expression=].
The statement can satisfy [=statically accessed|static access=] conditions in
a shader, but otherwise has no effect on the compiled shader.
This statement can be used at [=module scope=] and within [=function scope|functions=].

[=Type rule precondition=]:
The expression [=shader-creation error|must=] be of [=bool=] type.

<pre class=include>
path: syntax/const_assert_statement.syntax.bs.include
</pre>

<div class='example wgsl global-scope' heading="Static assertion examples">
  <xmp highlight=wgsl>
    const x = 1;
    const y = 2;
    const_assert x < y; // valid at module-scope.
    const_assert(y != 0); // parentheses are optional.

    fn foo() {
      const z = x + y - 2;
      const_assert z > 0; // valid in functions.
      let a  = 3;
      const_assert a != 0; // invalid, the expresion must be a const-expression.
    }
  </xmp>
</div>

## Statements Grammar Summary ## {#statements-summary}

The [=syntax/statement=] rule matches statements that can be used in most places inside a function body.

<pre class=include>
path: syntax/statement.syntax.bs.include
</pre>

<pre class=include>
path: syntax/variable_updating_statement.syntax.bs.include
</pre>

Additionally, certain statements may only be used in very specific contexts:
* [=syntax/break_if_statement=]
* [=syntax/continuing_compound_statement=]

## Statements Behavior Analysis ## {#behaviors}

### Rules ### {#behaviors-rules}

Some statements affecting control-flow are only valid in some contexts.
For example, [=statement/continue=] is invalid outside of a [=statement/loop=],
[=statement/for=], or [=statement/while=].
Additionally, the uniformity analysis (see [[#uniformity]]) needs to know when control flow can exit a statement in multiple different ways.

Both goals are achieved by a system for summarizing execution behaviors of statements. Behavior analysis maps each statement to the set of possible ways execution proceeds after evaluation of the statement completes.
As with type analysis for values and expressions, behavior analysis proceeds bottom up: first determine behaviors for certain basic statements, and then determine behavior for higher level constructs by applying combining rules.

A <dfn export>behavior</dfn> is a set, whose elements may be:
- Return
- Break
- Continue
- Next

Each of those correspond to a way to exit a compound statement: either through a keyword, or by falling to the next statement ("Next").

We note "*s*: *B*" to say that *s* respects the rules regarding behaviors, and has [=behavior=] *B*.

For each function:
- Its body [=shader-creation error|must=] be a valid statement by these rules.
- If the function has a return type, the [=behavior=] of its body [=shader-creation error|must=] be {Return}.
- Otherwise, the [=behavior=] of its body [=shader-creation error|must=] be a subset of {Next, Return}.

We assign a [=behavior=] to each function: it is its body's [=behavior=] (treating the body as a regular statement), with any "Return" replaced by "Next".
As a consequence of the rules above, a function behavior is always one of {}, or {Next}.

Behavior analysis [=shader-creation error|must=] be able to determine a
non-empty [=behavior=] for each statement, and function.

<table class='data'>
  <caption>Rules for analyzing and validating the behaviors of statements</caption>
  <thead>
    <tr><th>Statement<th>Preconditions<th>Resulting behavior
  </thead>
  <tr>
    <td class="nowrap">*empty statement*
    <td>
    <td class="nowrap">{Next}
  <tr algorithm="braced statement behavior">
    <td class="nowrap">{|s|}
    <td>|s|: |B|
    <td class="nowrap">|B|
  <tr algorithm="statement sequence behavior with next">
    <td class="nowrap" rowspan=2>|s1| |s2|

        Note: |s1| often ends in a semicolon.

    <td class="nowrap">|s1|: |B1|<br>
        Next in |B1|<br>
        |s2|: |B2|
    <td class="nowrap">(|B1|&#x2216;{Next}) &cup; |B2|
  <tr algorithm="statement sequence behavior without next">
    <td class="nowrap">|s1|: |B1|<br>
        Next not in |B1|<br>
        |s2|: <var ignore>B2</var>
    <td class="nowrap">|B1|
  <tr algorithm="variable declaration behavior">
    <td class="nowrap">var x:T;
    <td>
    <td>{Next}
  <tr algorithm="let-declaration behavior">
    <td class="nowrap">let x = |e|;
    <td>
    <td>{Next}
  <tr algorithm="initialized variable declaration behavior">
    <td class="nowrap">var x = |e|;
    <td>
    <td>{Next}
  <tr algorithm="assignment behavior">
    <td class="nowrap">x = |e|;
    <td>
    <td>{Next}
  <tr algorithm="phony assignment behavior">
    <td class="nowrap">_ = |e|;
    <td>
    <td>{Next}
  <tr algorithm="function call statement behavior">
    <td class="nowrap">|f|(|e1|, ..., |en|);
    <td class="nowrap">|f| has behavior |B|
    <td class="nowrap">|B|
  <tr algorithm="return behavior">
    <td>return;
    <td>
    <td>{Return}
  <tr algorithm="return value behavior">
    <td class="nowrap">return |e|;
    <td>
    <td>{Return}
  <tr algorithm="discard behavior">
    <td class="nowrap">discard;
    <td>
    <td>{Next}
  <tr algorithm="break behavior">
    <td>break;
    <td>
    <td>{Break}
  <tr algorithm="break if behavior">
    <td>break if |e|;
    <td>
    <td>{Break, Next}
  <tr algorithm="continue behavior">
    <td>continue;
    <td>
    <td>{Continue}
  <tr algorithm="const_assert behavior">
    <td>const_assert |e|;
    <td>
    <td>{Next}
  <tr algorithm="if statement behavior">
    <td class="nowrap">if |e| |s1| else |s2|
    <td class="nowrap">
        |s1|: |B1|<br>
        |s2|: |B2|
    <td class="nowrap">|B1| &cup; |B2|
  <tr algorithm="loop with continuing without break behavior">
    <td class="nowrap" rowspan=2>loop {|s1| continuing {|s2|}}
    <td class="nowrap">
        |s1|: |B1|<br>
        |s2|: |B2|<br>
        None of {Continue, Return} are in |B2|<br>
        Break is not in (|B1| &cup; |B2|)
    <td class="nowrap">(|B1| &cup; |B2|)&#x2216;{Continue, Next}
  <tr algorithm="loop with continuing with break behavior">
    <td class="nowrap">
        |s1|: |B1|<br>
        |s2|: |B2|<br>
        None of {Continue, Return} are in |B2|<br/>
        Break is in (|B1| &cup; |B2|)
    <td class="nowrap">(|B1| &cup; |B2| &cup; {Next})&#x2216;{Break, Continue}
  <tr algorithm="switch behavior">
    <td class="nowrap" rowspan=2>switch |e|  {case <var ignore>c1</var>: |s1| ... case <var ignore>cn</var>: |sn|}
    <td class="nowrap">
        |s1|: |B1|<br>
        ...<br>
        |sn|: |Bn|<br>
        Break is not in (|B1| &cup; ... &cup; |Bn|)
    <td class="nowrap">|B1| &cup; ... &cup; |Bn|
  <tr algorithm="switch with break behavior">
    <td class="nowrap">
        |s1|: |B1|<br>
        ...<br>
        |sn|: |Bn|<br>
        Break is in (|B1| &cup; ... &cup; |Bn|)
    <td class="nowrap">(|B1| &cup; ... &cup; |Bn| &cup; {Next})&#x2216;Break
</table>

Note: &cup; is a set union operation and &#x2216; is a set difference operation.

Note: The empty statement case occurs when a `loop` has an empty body, or when a `for` loop lacks an initialization or update statement.

For the purpose of this analysis:
- `for` loops get desugared (see [[#for-statement]])
- `while` loops get desugared (see [[#while-statement]])
- `loop {s}` is treated as `loop {s continuing {}}`
- `if` statements without an `else` branch are treated as if they had an empty else branch (which adds Next to their [=behavior=])
- `if` statements with `else if` branches are treated as if they were nested simple `if/else` statements
- a [=syntax/switch_clause=] starting with `default` behaves just like a [=syntax/switch_clause=] starting with `case _:`

Each [=built-in function=] has a [=behavior=] of {Next}.
And each operator application not listed in the table above has the same [=behavior=] as if it were a function call with the same operands and with a function's [=behavior=] of {Next}.

The behavior of a function [=shader-creation error|must=] satisfy the rules given above.

Note: It is unnecessary to analyze the behavior of expressions because they
will always be {Next} or a previously analyzed function will have produced
a error.

### Notes ### {#behaviors-notes}

This section is informative, non-normative.

Behavior analysis can cause a program to be rejected in the following ways
(restating requirements from above):
- The body of a function (treated as a regular statement) has a behavior not included in {Next, Return}.
- The body of a function with a return type has a behavior which is not {Return}.
- The behavior of a continuing block contains any of Continue, or Return.
- Some obviously infinite loops have an empty behavior set, and are therefore invalid.

This analysis can be run in linear time, by analyzing the call-graph bottom-up (since the behavior of a function call can depend on the function's code).

### Examples ### {#behaviors-examples}

Here are some examples showing this analysis in action:
<div class='example wgsl expect-error' heading='Trivially dead code is allowed'>
   <xmp highlight=wgsl>
    fn simple() -> i32 {
      var a: i32;
      return 0;  // Behavior: {Return}
      a = 1;     // Valid, statically unreachable code.
                 //   Statement behavior: {Next}
                 //   Overall behavior (due to sequential statements): {Return}
      return 2;  // Valid, statically unreachable code. Behavior: {Return}
    } // Function behavior: {Return}
   </xmp>
</div>

<div class='example wgsl expect-error' heading='Compound statements are supported'>
   <xmp highlight=wgsl>
    fn nested() -> i32 {
      var a: i32;
      {             // The start of a compound statement.
        a = 2;      // Behavior: {Next}
        return 1;   // Behavior: {Return}
      }             // The compound statement as a whole has behavior {Return}
      a = 1;        // Valid, statically unreachable code.
                    //   Statement behavior: {Next}
                    //   Overall behavior (due to sequential statements): {Return}
      return 2;     // Valid, statically unreachable code. Behavior: {Return}
    }
   </xmp>
</div>

<div class='example wgsl' heading='if/then behaves as if there is an empty else'>
   <xmp highlight=wgsl>
    fn if_example() {
      var a: i32 = 0;
      loop {
        if a == 5 {
          break;      // Behavior: {Break}
        }             // Behavior of the whole if compound statement: {Break, Next},
                      //   as the if has an implicit empty else
        a = a + 1;    // Valid, as the previous statement had "Next" in its behavior
      }
    }
   </xmp>
</div>

<div class='example wgsl expect-error' heading='if/then/else has the behavior of both sides'>
   <xmp highlight=wgsl>
    fn if_example() {
      var a: i32 = 0;
      loop {
        if a == 5 {
          break;      // Behavior: {Break}
        } else {
          continue;   // Behavior: {Continue}
        }             // Behavior of the whole if compound statement: {Break, Continue}
        a = a + 1;    // Valid, statically unreachable code.
                      //   Statement behavior: {Next}
                      //   Overall behavior: {Break, Continue}
      }
    }
   </xmp>
</div>

<div class='example wgsl' heading='if/else if/else behaves like a nested if/else'>
   <xmp highlight=wgsl>
    fn if_example() {
      var a: i32 = 0;
      loop {
        // if e1 s1 else if e2 s2 else s3
        // is identical to
        // if e1 else { if e2 s2 else s3 }
        if a == 5 {
          break;      // Behavior: {Break}
        } else if a == 42 {
          continue;   // Behavior: {Continue}
        } else {
          return;     // Behavior {Return}
        }             // Behavior of the whole if compound statement:
                      //   {Break, Continue, Return}
      }               // Behavior of the whole loop compound statement {Next, Return}
    }                 // Behavior of the whole function {Next}
   </xmp>
</div>

<div class='example wgsl' heading='Break in switch becomes Next'>
   <xmp highlight=wgsl>
    fn switch_example() {
      var a: i32 = 0;
      switch a {
        default: {
          break;   // Behavior: {Break}
        }
      }            // Behavior: {Next}, as switch replaces Break by Next
      a = 5;       // Valid, as the previous statement had Next in its behavior
    }
   </xmp>
</div>

<div class='example wgsl' heading='Obviously infinite loops'>
   <xmp highlight=wgsl>
    fn invalid_infinite_loop() {
      loop { }     // Behavior: { }.  Invalid because it's empty.
    }
   </xmp>
</div>

<div class='example wgsl' heading='Discard will not terminate a loop'>
  <xmp highlight=wgsl>
    fn invalid_infinite_loop() {
      loop {
        discard; // Behavior { Next }.
      }          // Invalid, behavior of the whole loop is { }.
    }
  </xmp>
</div>

<div class='example wgsl' heading='A conditional continue with continuing statement'>
   <xmp highlight=wgsl>
    fn conditional_continue() {
      var a: i32;
      loop {
        if a == 5 { break; } // Behavior: {Break, Next}
        if a % 2 == 1 {      // Valid, as the previous statement has Next in its behavior
          continue;          // Behavior: {Continue}
        }                    // Behavior: {Continue, Next}
        a = a * 2;           // Valid, as the previous statement has Next in its behavior
        continuing {         // Valid as the continuing statement has behavior {Next}
                             //  which does not include any of:
                             //  {Break, Continue, Return}
          a = a + 1;
        }
      }                      // The loop as a whole has behavior {Next},
                             //  as it absorbs "Continue" and "Next",
                             //  then replaces "Break" with "Next"
    }
   </xmp>
</div>

<div class='example wgsl' heading='A redundant continue with continuing statement'>
   <xmp highlight=wgsl>
    fn redundant_continue_with_continuing() {
      var a: i32;
      loop {
        if a == 5 { break; }
        continue;   // Valid. This is redundant, branching to the next statement.
        continuing {
          a = a + 1;
        }
      }
    }
   </xmp>
</div>

<div class='example wgsl' heading='A continue at the end of a loop body'>
   <xmp highlight=wgsl>
    fn continue_end_of_loop_body() {
      for (var i: i32 = 0; i < 5; i++ ) {
        continue;   // Valid. This is redundant,
                    //   branching to the end of the loop body.
      }             // Behavior: {Next},
                    //   as loops absorb "Continue",
                    //   and "for" loops always add "Next"
    }
   </xmp>
</div>
`for` loops desugar to `loop` with a conditional break. As shown in a previous example, the conditional break has [=behavior=] {Break, Next}, which leads to adding "Next" to the loop's [=behavior=].

<div class='example wgsl expect-error' heading='return required in functions that have a return type'>
   <xmp highlight=wgsl>
    fn missing_return () -> i32 {
      var a: i32 = 0;
      if a == 42 {
        return a;       // Behavior: {Return}
      }                 // Behavior: {Next, Return}
    }                   // Error: Next is invalid in the body of a
                        //   function with a return type
   </xmp>
</div>

<div class='example wgsl expect-error' heading='continue must be in a loop'>
   <xmp highlight=wgsl>
    fn continue_out_of_loop () {
      var a: i32 = 0;
      if a > 0  {
        continue;       // Behavior: {Continue}
      }                 // Behavior: {Next, Continue}
    }                   // Error: Continue is invalid in the body of a function
   </xmp>
</div>
The same example would also be invalid for the same reason if `continue` was replaced by `break`.

# Functions # {#functions}

A <dfn dfn-for="function" noexport>function</dfn> performs computational work when invoked.

A function is invoked in one of the following ways:
* By evaluating a function call expression. See [[#function-call-expr]].
* By executing a function call statement. See [[#function-call-statement]].
* An [=entry point=] function is invoked by the WebGPU implementation to perform
    the work of a [=shader stage=] in a [=pipeline=]. See [[#entry-points]]

Functions in WGSL may be defined in any order, including later in the source than they are used.
Because of this, function prototypes or forward declarations are not needed, and there is no way to do so.

There are two kinds of functions:
* A [=built-in function=] is provided by the WGSL implementation,
    and is always available to a WGSL module.
    See [[#builtin-functions]].
* A [=user-defined function=] is declared in a WGSL module.

## Declaring a User-defined Function ## {#function-declaration-sec}

A <dfn noexport>function declaration</dfn> creates a <dfn noexport>user-defined function</dfn>, by specifying:
* An optional set of [=attributes=].
* The name of the function.
* The formal parameter list: an ordered sequence of zero
    or more [=formal parameter=] declarations,
    which may have attributes applied,
    separated by commas, and
    surrounded by parentheses.
* An optional <dfn noexport>return type</dfn>, which may have attributes applied.
* The <dfn noexport>function body</dfn>.
    This is the set of statements to be executed when the function is [=function call|called=].

A function declaration [=shader-creation error|must=] only occur at [=module scope=].
A function name is [=in scope=] for the entire program.

Note: Each [=user-defined function=] only has one [=overload=].

A <dfn noexport>formal parameter</dfn> [=declaration=] specifies an [=identifier=] name and a type for a value that [=shader-creation error|must=] be
provided when invoking the function.
A formal parameter may have attributes.
See [[#function-calls]].
The [=scope=] of the identifier is the [=function body=].
Two formal parameters for a given function [=shader-creation error|must not=] have the same name.

Note: Some built-in functions may allow parameters to be [=abstract numeric types=];
however, this functionality is not currently supported for user-declared
functions.

The [=return type=], if specified, [=shader-creation error|must=] be [=constructible=].

WGSL defines the following attributes that can be applied to function declarations:
 * the [=shader stage attributes=]: [=attribute/vertex=], [=attribute/fragment=], and [=attribute/compute=]
 * [=attribute/workgroup_size=]

WGSL defines the following attributes that can be applied to function
parameters and return types:
 * [=attribute/builtin=]
 * [=attribute/location=]
 * [=attribute/blend_src=]
 * [=attribute/interpolate=]
 * [=attribute/invariant=]

<pre class=include>
path: syntax/function_decl.syntax.bs.include
</pre>
<pre class=include>
path: syntax/function_header.syntax.bs.include
</pre>
<pre class=include>
path: syntax/param_list.syntax.bs.include
</pre>
<pre class=include>
path: syntax/param.syntax.bs.include
</pre>

<div class='example wgsl' heading='Simple functions'>
  <xmp highlight=wgsl>
    // Declare the add_two function.
    // It has two formal parameters, i and b.
    // It has a return type of i32.
    // It has a body with a return statement.
    fn add_two(i: i32, b: f32) -> i32 {
      return i + 2;  // A formal parameter is available for use in the body.
    }

    // A compute shader entry point function, 'main'.
    // It has no specified return type.
    // It invokes the add_two function, and captures
    // the resulting value in the named value 'six'.
    @compute @workgroup_size(1)
    fn main() {
       let six: i32 = add_two(4, 5.0);
    }
  </xmp>
</div>

## Function Calls ## {#function-calls}

A <dfn noexport>function call</dfn> is a statement or expression which invokes a function.

The function containing the function call is the <dfn>calling function</dfn>, or <dfn noexport>caller</dfn>.
The function being invoked is the <dfn>called function</dfn>, or <dfn noexport>callee</dfn>.

The function call:
* Names the [=called function=], and
* Provides a parenthesized, comma-separated list of argument value expressions.

The function call [=shader-creation error|must=] supply the same number of argument values as there are
[=formal parameter|formal parameters=] in the [=called function=].
Each argument value [=shader-creation error|must=] evaluate to the same type as the corresponding formal
parameter, by position.

In summary, when calling a function:
1. Execution of the [=calling function=] is suspended.
2. The [=called function=] executes until it [=returns=].
3. Execution of the [=calling function=] resumes.

A called function <dfn>returns</dfn> as follows:
* A [=built-in function=] returns when its work has completed.
* A [=user-defined function=] with a [=return type=] returns when it executes a [=statement/return=] statement.
* A [=user-defined function=] with no [=return type=] returns when it executes a [=statement/return=] statement,
    or when execution reaches the end of its [=function body=].

In detail, when a function call is executed the following steps occur:
1. Function call argument values are evaluated.
    The relative order of evaluation is left-to-right.
2. Execution of the [=calling function=] is suspended.
    All [=function scope=] variables and constants maintain their current values.
3. If the called function is [=user-defined function|user-defined=],
    memory is allocated for each function scope variable in the called function.
    * Initialization occurs as described in [[#var-decls]].
4. Values for the formal parameters of the called function are determined
    by matching the function call argument values by position.
    For example, the first formal parameter of the called function will have
    the value of the first argument at the [=call site=].
5. Control is transferred to the called function.
    If the called function is [=user-defined function|user-defined=], execution
    proceeds starting from the first statement in the [=function body|body=].
6. The called function is executed, until it [=returns=].
7. Control is transferred back to the calling function, and the called function's execution is
    unsuspended.
    If the called function [=return value|returns a value=], that value is supplied for the
    value of the function call expression.

The location of a function call is referred to as a <dfn noexport>call site</dfn>, specifically
the location of the first [=token=] in the parsed instance of the [=syntax/call_phrase=] grammar rule.
Call sites are a [=dynamic context=].
As such, the same textual location may represent multiple call sites.

Note: It is possible that a function call in a [=fragment=] shader never
returns if all of the invocations in a [=quad=] are [=statement/discard|discarded=].
In such a case, control will not be tranferred back to the calling function.

## `const` Functions ## {#const-funcs}

A function declared with a [=attribute/const=] attribute can be
evaluated at [=shader module creation|shader-creation time=].
These functions are called <dfn noexport>const-functions</dfn>.
Calls to these functions can be part of [=const-expressions=].

It is a [=shader-creation error=] if the function contains any expressions that
are not [=const-expressions=], or any declarations that are not
[=const-declarations=].

Note: The [=attribute/const=] attribute cannot be applied to user-declared functions.

<div class='example wgsl' heading='const-functions'>
  <xmp highlight=wgsl>
    const first_one = firstLeadingBit(1234 + 4567); // Evaluates to 12
                                                    // first_one has the type i32, because
                                                    // firstLeadingBit cannot operate on
                                                    // AbstractInt

    @id(1) override x : i32;
    override y = firstLeadingBit(x); // const-expressions can be
                                     // used in override-expressions.
                                     // firstLeadingBit(x) is not a
                                     // const-expression in this context.

    fn foo() {
      var a : array<i32, firstLeadingBit(257)>; // const-functions can be used in
                                                // const-expressions if all their
                                                // parameters are const-expressions.
    }
  </xmp>
</div>

## Restrictions on Functions ## {#function-restriction}

* A [=vertex=] shader [=shader-creation error|must=] return the [=built-in values/position=] [=built-in output value=].
* An entry point [=shader-creation error|must=] never be the target of a [=function call=].
* If a function has a return type, it [=shader-creation error|must=] be a [=constructible=] type.
* A [=formal parameter|function parameter=] [=shader-creation error|must=] one the following types:
    * a constructible type
    * a pointer type
    * a texture type
    * a sampler type
* Each function call argument [=shader-creation error|must=] evaluate to the type of the corresponding
    function parameter.
    * In particular, an argument that is a pointer [=shader-creation error|must=] agree with the formal parameter
        on [=address space=], [=store type=], and [=access mode=].

Note: Recursion is disallowed because cycles are not permitted among any kinds
of declarations.

<div class='example wgsl' heading='Valid and invalid pointer arguments'>
  <xmp highlight=wgsl>
    fn bar(p : ptr<function, f32>) {
    }

    fn baz(p : ptr<private, i32>) {
    }

    fn bar2(p : ptr<function, f32>) {
      let a = &*&*(p);

      bar(p); // Valid
      bar(a); // Valid
    }

    fn baz2(p : ptr<storage, f32>) {
    }

    struct S {
      x : i32
    }

    @group(0) @binding(0)
    var<storage> ro_storage : f32;
    @group(0) @binding(1)
    var<storage, read_write> rw_storage : f32;

    var usable_priv : i32;
    var unusable_priv : array<i32, 4>;
    fn foo() {
      var usable_func : f32;
      var unusable_func : S;
      var i32_func : i32;

      let a_priv = &usable_priv;
      let b_priv = a_priv;
      let c_priv = &*&usable_priv;
      let d_priv = &(unusable_priv.x);
      let e_priv = d_priv;

      let a_func = &usable_func;
      let b_func = &unusable_func;
      let c_func = &(*b_func)[0];
      let d_func = c_func;
      let e_func = &*a_func;

      baz(&usable_priv); // Valid, address-of a variable.
      baz(a_priv);       // Valid, effectively address-of a variable.
      baz(b_priv);       // Valid, effectively address-of a variable.
      baz(c_priv);       // Valid, effectively address-of a variable.
      baz(d_priv);       // Valid, memory view has changed.
      baz(e_priv);       // Valid, memory view has changed.
      baz(&i32_func);    // Invalid, address space mismatch.

      bar(&usable_func); // Valid, address-of a variable.
      bar(c_func);       // Valid, memory view has changed.
      bar(d_func);       // Valid, memory view has changed.
      bar(e_func);       // Valid, effectively address-of a variable.

      baz2(&ro_storage); // Valid, address-of a variable.
      baz2(&rw_storage); // Invalid, access mode mismatch.
    }
  </xmp>
</div>

### Alias Analysis ### {#alias-analysis}

#### Root Identifier #### {#root-ident-sec}

[=Memory locations=] can be accessed during the execution of a function using [=memory views=].
Within a function, each [=memory view=] has a particular <dfn>root identifier</dfn>, which names
the variable or formal parameter that first provides access to that memory in that function.

Locally derived expressions of [=reference type|reference=] or
[=pointer type|pointer=] type may introduce new names for a particular root identifier,
but each expression has a statically determinable root identifier.

<p algorithm="finding a root identifier">
Given an expression |E| of [=pointer type|pointer=] or [=reference type=], the
[=root identifier=] is the [=originating variable=] or [=formal parameter=] of [=pointer type=]
found as follows:
* If |E| is an identifier [=resolves|resolving=] to a variable, then the root identifier is that variable.
* If |E| is an identifier [=resolves|resolving=] to a formal parameter of pointer type, then the root identifier is that formal parameter.
* If |E| is an identifier [=resolves|resolving=] to a [=let-declaration=] with initializer |E2|, then the root identifier is the root identifier of |E2|.
* If |E| is of the form `(`|E2|`)`, `&`|E2|, `*`|E2|, or |E2|`[`<var ignore>Ei</var>`]` then the root identifier is the root identifier of |E2|.
* If |E| is a [[#vector-access-expr|vector access expression]] of the form |E2|.|swiz|, where |swiz| is a [=swizzle=] name, then the root identifer is the root identifier of |E2|.
* If |E| is a [[#struct-access-expr|structure access expression]] of the form |E2|.<var ignore>member_name</var>, then the root identifer is the root identifier of |E2|.
    <p>

#### Aliasing #### {#aliasing}

While the [=originating variable=] of a [=root identifier=] is a dynamic concept that
depends on the [=call sites=] for the function, WGSL modules can be
statically analyzed to determine the set of all possible [=originating
variables=] for each root identifier.

Two [=root identifiers=] <dfn noexport>alias</dfn> when they have the same
[=originating variable=].
Execution of a WGSL function [=shader-creation error|must not=] potentially
access memory through aliased root identifiers, where one access is a write and
the other is a read or a write.
This is determined by analyzing the program from the leaves of the callgraph
upwards (i.e. topological order).
For each function the analysis records the following sets:
* [=module scope|Module-scope=] variables that are [=write access|written=].
    This includes any module-scope variables that are written in functions called from this function.
* [=module scope|Module-scope=] variables that are [=read access|read=].
    This includes any module-scope variables that are read in functions called from this function.
* Pointer parameters used as root identifiers of memory views that are [=write access|written=] in this function or in called functions.
* Pointer parameters used as root identifiers of memory views that are [=read
    access|read=] in this function or in called functions.

At each [=call site=] of a function, it is a [=shader-creation error=] if any
of the following occur:
* Two arguments of pointer type have the same root identifier and either
    corresponding parameter is in the written parameter set.
* An argument of pointer type whose root identifier is a module-scope variable where:
    * the corresponding pointer parameter is in the set of written pointer parameters, and
    * the module-scope variable is in the read set for the called function.
* An argument of pointer type whose root identifier is a module-scope variable where:
    * the corresponding pointer parameter is in the set of written pointer parameters, and
    * the module-scope variable is in the written set for the called function.
* An argument of pointer type whose root identifier is a module-scope variable where:
    * the corresponding pointer parameter is in the set of read pointer parameters, and
    * the module-scope variable is in the written set for the called function.

<div class='example wgsl' heading='Alias analysis'>
  <xmp highlight=wgsl>
    var<private> x : i32 = 0;

    fn f1(p1 : ptr<function, i32>, p2 : ptr<function, i32>) {
      *p1 = *p2;
    }

    fn f2(p1 : ptr<function, i32>, p2 : ptr<function, i32>) {
      f1(p1, p2);
    }

    fn f3() {
      var a : i32 = 0;
      f2(&a, &a);  // Invalid. Cannot pass two pointer parameters
                   // with the same root identifier when one or
                   // more are written (even by a subfunction).
    }

    fn f4(p1 : ptr<function, i32>, p2 : ptr<function, i32>) -> i32 {
      return *p1 + *p2;
    }

    fn f5() {
      var a : i32 = 0;
      let b = f4(&a, &a); // Valid. p1 and p2 in f4 are both only read.
    }

    fn f6(p : ptr<private, i32>) {
      x = *p;
    }

    fn f7(p : ptr<private, i32>) -> i32 {
      return x + *p;
    }

    fn f8() {
      let a = f6(&x); // Invalid. x is written as a global variable and
                      // read as a parameter.
      let b = f7(&x); // Valid. x is only read as both a parameter and
                      // a variable.
    }
  </xmp>
</div>

# Attributes # {#attributes}

An <dfn noexport>attribute</dfn> modifies an object.
WGSL provides a unified syntax for applying attributes.
Attributes are used for a variety of purposes such as specifying the interface with the API.

Generally speaking, from the language's point-of-view, attributes can be
ignored for the purposes of type and semantic checking.
Additionally, the attribute name is a [=context-dependent name=], and
some attribute parameters are also context-dependent names.

<pre class=include>
path: syntax/attribute.syntax.bs.include
</pre>

Unless explicitly permitted in an attribute's description, an attribute [=shader-creation error|must not=] be specified more than once per object or type.

## `align` ## {#align-attr}

<pre class=include>
path: syntax/align_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`align`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>Constrains the placement of a structure member in memory.

    [=shader-creation error|Must=] only be applied to a member of a [=structure=] type.

    Note: This attribute influences how a value of the enclosing structure type can appear in memory:
    at which byte addresses the structure itself and its component members can appear.
    In particular, the rules in [[#memory-layouts]] combine to imply the following constraint:

    <p class="note" algorithm="implied constraint on align attribute">
    If `align(`|n|`)` is applied to a member of |S|
    with type |T|, and |S| is the [=store type=]
    or contained in the store type for a variable in address space |C|,
    then |n| [=shader-creation error|must=] satisfy:
    |n|&nbsp;=&nbsp;|k|&nbsp;&times;&nbsp;[=RequiredAlignOf=](|T|,|C|)
    for some positive integer |k|.
    </p>

  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=type rules|resolves=] to an [=i32=] or [=u32=].<br>
        [=shader-creation error|Must=] be positive.<br>
        [=shader-creation error|Must=] be a power of 2.

</table>

## `binding` ## {#binding-attr}

<pre class=include>
path: syntax/binding_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`binding`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    Specifies the binding number of the resource in a bind [=attribute/group=].
    See [[#resource-interface]].

    [=shader-creation error|Must=] only be applied to a [=resource=] variable.
  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=type rules|resolves=] to an [=i32=] or [=u32=].<br>
        [=shader-creation error|Must=] be non-negative.

</table>

## `blend_src` ## {#blend-src-attr}

<pre class=include>
path: syntax/blend_src_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`blend_src`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    Specifies a part of the [=fragment=] output when the feature [=extension/dual_source_blending=]
    is enabled.
    See [[#input-output-locations]].

    [=shader-creation error|Must=] only be applied to a member of a [=structure=] type with a
    [=attribute/location=] attribute.
    [=shader-creation error|Must=] only be applied to declarations of objects with [=numeric scalar=]
    or [=numeric vector=] type.
    [=shader-creation error|Must not=] be included in a [=shader stage input=].
    [=shader-creation error|Must not=] be included in a [=shader stage output=],
    except for the [=fragment=] shader stage.

  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=resolves=] to an [=i32=] or [=u32=] with value of `0` or `1`.

</table>

## `builtin` ## {#builtin-attr}

<pre class=include>
path: syntax/builtin_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`builtin`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>Specifies that the associated object is a built-in value, as denoted by the specified [=token=].
    See [[#builtin-inputs-outputs]].

    [=shader-creation error|Must=] only be applied to an entry point
    function parameter, entry point return type, or member of a [=structure=].
  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=built-in value name-token=] for a [=built-in value=].

</table>

## `const` ## {#const-attr}

<pre class=include>
path: syntax/const_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`const`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    Specifies that the function can be used as a [=const-function=].
    This attribute [=shader-creation error|must not=] be applied to a
    user-defined function.

    [=shader-creation error|Must=] only be applied to function declarations.

    Note: This attribute is used as a notational convention to describe which
    built-in functions can be used in [=const-expressions=].
  <tr>
    <td>Parameters
    <td>*None*

</table>

## `diagnostic` ## {#diagnostic-attr}

<pre class=include>
path: syntax/diagnostic_attr.syntax.bs.include
</pre>
<pre class=include>
path: syntax/diagnostic_control.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`diagnostic`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>Specifies a [=range diagnostic filter=].  See [[#diagnostics]].

        More than one [=attribute/diagnostic=] attribute may be specified on a syntactic form,
        but they [=shader-creation error|must=] specify different [=diagnostic/triggering rules=].

  <tr>
    <td>Parameters
    <td>The first parameter is a [=syntax/severity_control_name=].

        The second parameter is a [=syntax/diagnostic_rule_name=] token
        specifying a [=diagnostic/triggering rule=].
</table>

## `group` ## {#group-attr}

<pre class=include>
path: syntax/group_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`group`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    Specifies the binding group of the resource.
    See [[#resource-interface]].

    [=shader-creation error|Must=] only be applied to a [=resource=] variable.
  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=type rules|resolves=] to an [=i32=] or [=u32=].<br>
        [=shader-creation error|Must=] be non-negative.

</table>

## `id` ## {#id-attr}

<pre class=include>
path: syntax/id_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`id`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    Specifies a numeric identifier as an alternate name for a
    [=pipeline-overridable=] constant.

    [=shader-creation error|Must=] only be applied to an [=override-declaration=] of [=scalar=] type.
  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=type rules|resolves=] to an [=i32=] or [=u32=].<br>
        [=shader-creation error|Must=] be non-negative.

</table>

## `interpolate` ## {#interpolate-attr}

<pre class=include>
path: syntax/interpolate_attr.syntax.bs.include
</pre>

<pre class=include>
path: syntax/interpolate_type_name.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`interpolate`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description

    <td>Specifies how the user-defined IO [=shader-creation error|must=] be interpolated.
    The attribute is only significant on user-defined [=vertex=] outputs
    and [=fragment=] inputs.
    See [[#interpolation]].

    [=shader-creation error|Must=] only be applied to a declaration that
    has a [=attribute/location=] attribute applied.
  <tr>
    <td>Parameters
    <td>The first parameter [=shader-creation error|must=] be an
    [=interpolation type name-token=] for an [=interpolation type=].

    The second parameter, if present, [=shader-creation error|must=] be
    an [=interpolation sampling name-token=] for the [=interpolation sampling=].

</table>

## `invariant` ## {#invariant-attr}

<pre class=include>
path: syntax/invariant_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`invariant`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    When applied to the [=built-in values/position=] [=built-in output value=] of a vertex
    shader, the computation of the result is invariant across different
    programs and different invocations of the same entry point.
    That is, if the data and control flow match for two `position` outputs in
    different entry points, then the result values are guaranteed to be the
    same.
    There is no effect on a `position` [=built-in input value=].

    [=shader-creation error|Must=] only be applied to the [=built-in values/position=] built-in value.

    Note: This attribute maps to the `precise` qualifier in HLSL, and the
    `invariant` qualifier in GLSL.
  <tr>
    <td>Parameters
    <td>*None*

</table>

## `location` ## {#location-attr}

<pre class=include>
path: syntax/location_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`location`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
    Specifies a part of the user-defined IO of an entry point.
    See [[#input-output-locations]].

    [=shader-creation error|Must=] only be applied to an entry point function parameter, entry point
    return type, or member of a [=structure=] type.
    [=shader-creation error|Must=] only be applied to declarations of objects with [=numeric scalar=]
    or [=numeric vector=] type.
    [=shader-creation error|Must not=] be included in [=compute=] [=shader stage inputs=].

  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=type rules|resolves=] to an [=i32=] or [=u32=].<br>
        [=shader-creation error|Must=] be non-negative.

</table>

## `must_use` ## {#must-use-attr}

<pre class=include>
path: syntax/must_use_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`must_use`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>
        Specifies that a [=function call|call=] to this function [=shader-creation error|must=] be used as an [=expression=].
        That is, a call to this function [=shader-creation error|must=] not be the entirety of a [[#function-call-statement|function call statement]].

        [=shader-creation error|Must=] only be applied to the declaration of a [=function/function=] with a [=return type=].

        Note: Many functions return a value and do not have side effects.
        It is often a programming defect to call such a function as the only thing in a function call statement.
        Built-in functions with these properties are declared as `@must_use`.
        User-defined functions can also have the `@must_use` attribute.

        Note: To deliberately work around the `@must_use` rule, use a [=phony assignment=]
        or [=value declaration|declare a value=] using the function call as the initializer.

  <tr>
    <td>Parameters
    <td>*None*

</table>

## `size` ## {#size-attr}

<pre class=include>
path: syntax/size_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`size`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>Specifies the number of bytes reserved for a structure member.

    This number [=shader-creation error|must=] be at least the [=byte-size=] of the type of the member:
    <p algorithm="byte-size constraint">
    If `size(`|n|`)` is applied to a member with type |T|, then [=SizeOf=](|T|)&nbsp;&leq;&nbsp;|n|.
    </p>

    See [[#memory-layouts]].

    [=shader-creation error|Must=] only be applied to a member of a [=structure=] type.
    The member type [=shader-creation error|must=] have [=creation-fixed footprint=].
  <tr>
    <td>Parameters
    <td>[=shader-creation error|Must=] be a [=const-expression=] that [=type rules|resolves=] to an [=i32=] or [=u32=].<br>
        [=shader-creation error|Must=] be positive.

</table>

## `workgroup_size` ## {#workgroup-size-attr}

<pre class=include>
path: syntax/workgroup_size_attr.syntax.bs.include
</pre>

<table class='data builtin'>
  <caption><dfn noexport dfn-for="attribute">`workgroup_size`</dfn> Attribute</caption>
  <tr>
    <td style="width:10%">Description
    <td>Specifies the x, y, and z dimensions of the [=workgroup grid=] for the compute shader.

    The first parameter specifies the x dimension.
    The second parameter, if provided, specifies the y dimension, otherwise is assumed to be 1.
    The third parameter, if provided, specifies the z dimension, otherwise is assumed to be 1.

    [=shader-creation error|Must=] only be applied to a [=compute shader stage|compute shader=] entry point function.
    [=shader-creation error|Must not=] be applied to any other object.

  <tr>
    <td>Parameters
    <td>Takes one, two, or three parameters.

        Each parameter [=shader-creation error|must=] be a [=const-expression=] or an [=override-expression=].
        All parameters [=shader-creation error|must=] be the same type, either [=i32=] or [=u32=].

        A [=shader-creation error=] results if any specified parameter is a
        [=const-expression=] that evaluates to a non-positive value.

        A [=pipeline-creation error=] results if any specified parameter evaluates
        to a non-positive value or exceeds an upper bound specified by the WebGPU
        API, or if the product of the parameter values exceeds the upper bound
        specified by the WebGPU API (see [[WebGPU#limits]]).

</table>

## Shader Stage Attributes ## {#shader-stage-attr}

The <dfn noexport>shader stage attributes</dfn> below
designate a function as an [=entry point=] for a particular [=shader stage=].
These attributes [=shader-creation error|must=] only be applied to [=function declarations=],
and at most one may be present on a given function.
They take no parameters.

### `vertex` ### {#vertex-attr}

<pre class=include>
path: syntax/vertex_attr.syntax.bs.include
</pre>

The <dfn noexport dfn-for="attribute">`vertex`</dfn> attribute declares the function to be an
[=entry point=] for the [=vertex shader stage=] of a [=GPURenderPipeline|render pipeline=].

### `fragment` ### {#fragment-attr}

<pre class=include>
path: syntax/fragment_attr.syntax.bs.include
</pre>

The <dfn noexport dfn-for="attribute">`fragment`</dfn> attribute declares the function to be an
[=entry point=] for the [=fragment shader stage=] of a [=GPURenderPipeline|render pipeline=].

### `compute` ### {#compute-attr}

<pre class=include>
path: syntax/compute_attr.syntax.bs.include
</pre>

The <dfn noexport dfn-for="attribute">`compute`</dfn> attribute declares the function to be an
[=entry point=] for the [=compute shader stage=] of a [=GPUComputePipeline|compute pipeline=].

# Entry Points # {#entry-points}

An <dfn noexport>entry point</dfn> is a [=user-defined function=] that performs
the work for a particular [=shader stage=].

## Shader Stages ## {#shader-stages-sec}

WebGPU issues work to the GPU in the form of [=draw command|draw=] or [=dispatch commands=].
These commands execute a pipeline in the context of a set of shader stage
[=shader stage input|inputs=], [=shader stage output|outputs=], and attached
[=resources=].

A <dfn noexport>pipeline</dfn> describes the work to be performed on the GPU, as a sequence
of stages, some of which are programmable.
In WebGPU, a pipeline is created before scheduling a draw or dispatch command for execution.
There are two kinds of pipelines: GPUComputePipeline, and GPURenderPipeline.

A [=dispatch command=] uses a <dfn noexport>GPUComputePipeline</dfn> to run a
<dfn noexport>compute shader stage</dfn> over a logical
grid of points with a controllable amount of parallelism,
while reading and possibly updating buffer and image resources.

A [=draw command=] uses a <dfn noexport>GPURenderPipeline</dfn> to run a multi-stage process with
two programmable stages among other fixed-function stages:

* A <dfn noexport>vertex shader stage</dfn> maps input attributes for a single vertex into
    output attributes for the vertex.
* Fixed-function stages map vertices into graphic primitives (such as triangles)
    which are then rasterized to produce fragments.
* A <dfn noexport>fragment shader stage</dfn> processes each fragment,
    possibly producing a fragment output.
* Fixed-function stages consume a fragment output, possibly updating external state
    such as color attachments and depth and stencil buffers.

The WebGPU specification describes pipelines in greater detail.

WGSL defines three <dfn noexport>shader stages</dfn>, corresponding to the
programmable parts of pipelines:

* <dfn noexport>compute</dfn>
* <dfn noexport>vertex</dfn>
* <dfn noexport>fragment</dfn>

Each shader stage has its own set of features and constraints, described elsewhere.

## Entry Point Declaration ## {#entry-point-decl}

To create an [=entry point=], declare a [=user-defined function=] with a [=shader stage attribute=].

When configuring a [=pipeline=] in the WebGPU API,
the entry point's function name maps to the `entryPoint` attribute of the
WebGPU {{GPUProgrammableStage}} object.

The entry point's [=formal parameters=] denote the stage's [=shader stage inputs=].
The entry point's [=return value=], if specified, denotes the stage's [=shader stage outputs=].

The type of each formal parameter, and the entry point's return type, [=shader-creation error|must=] be one of:
* [=bool=]
* a [=numeric scalar=]
* a [=numeric vector=]
* a [=structure=] whose member types are any of [=bool=], [=numeric scalar=], or [=numeric vector=].

A structure type can be used to group [=user-defined input datum|user-defined inputs=] with each other and optionally with [=built-in input value|built-in inputs=].
A structure type can be used as the [=return type=] to group [=user-defined output datum|user-defined outputs=] with each other and optionally with [=built-in output value|built-in outputs=].

Note: The [=bool=] case is forbidden for user-defined inputs and outputs.
It is only permitted for the [=built-in values|front_facing builtin value=].

Note: [=Compute=] entry points never have a return type.

<div class='example wgsl global-scope' heading='Entry Point'>
  <xmp highlight=wgsl>
    @vertex
    fn vert_main() -> @builtin(position) vec4<f32> {
      return vec4<f32>(0.0, 0.0, 0.0, 1.0);
    }

    @fragment
    fn frag_main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
      return vec4<f32>(coord_in.x, coord_in.y, 0.0, 1.0);
    }

    @compute @workgroup_size(1)
    fn comp_main() { }
  </xmp>
</div>

The set of <dfn noexport>functions in a shader stage</dfn> is the union of:

* The entry point function for the stage.
* The targets of function calls from within the body of a function
    in the shader stage, whether or not that call is executed.

The union is applied repeatedly until it stabilizes.
It will stabilize in a finite number of steps.

### Function Attributes for Entry Points ### {#entry-point-attributes}

WGSL defines the following attributes that can be applied to entry point declarations:
 * the [=shader stage attributes=]: [=attribute/vertex=], [=attribute/fragment=], and [=attribute/compute=]
 * [=attribute/workgroup_size=]

<div class='example wgsl global-scope' heading='workgroup_size Attribute'>
  <xmp highlight=wgsl>
    @compute @workgroup_size(8,4,1)
    fn sorter() { }

    @compute @workgroup_size(8u)
    fn reverser() { }

    // Using an pipeline-overridable constant.
    @id(42) override block_width = 12u;
    @compute @workgroup_size(block_width)
    fn shuffler() { }

    // Error: workgroup_size must be specified on compute shader
    @compute
    fn bad_shader() { }
  </xmp>
</div>

## Shader Interface ## {#shader-interface}

The shader interface is the set of objects
through which the shader accesses data external to the [=shader stage=],
either for reading or writing, and the [=pipeline-overridable=] constants used to configure the shader.
The interface includes:

* [=Shader stage inputs=]
* [=Shader stage outputs=]
* [=Override-declarations=]
* Attached [=resources=], which include:
    * [=Uniform buffers=]
    * [=Storage buffers=]
    * [=Texture resources=]
    * [=Sampler resources=]

A declaration *D* is <dfn>statically accessed</dfn> by a shader when:
* An identifier [=resolves|resolving=] to *D* appears in the [=function declaration|declaration=]
    of any of the [=functions in a shader stage|functions in the shader stage=].
* An identifier [=resolves|resolving=] to *D* is used to define a type for a [=statically accessed=] declaration.
* An identifier [=resolves|resolving=] to *D* is used in the initializer for a [=statically accessed=] declaration.
* An identifier [=resolves|resolving=] to *D* is used by an attribute used by a [=statically accessed=] declaration.

<div class="note"><span class=marker>Note:</span>Static access is recursively defined, taking into account the following:
* All the parts of a [=function declaration=] including attributes, formal parameters, return type, and function body.
* Any type needed to define the above, including following [=type aliases=].
* As a particular case of helping to define a type,
    any [=override-declaration=] used in an [=override-expression=] that is the [=element count=]
    of an [=array=] type for a variable in the [=address spaces/workgroup=] address space,
    when that variable itself is statically accessed.
* Any override declarations used to support the evaluation of override-expressions in any of the above.
* Any attributes on any of the above.
    </div>

We can now precisely define the <dfn noexport>interface of a shader</dfn> as consisting of:
  - The [=formal parameters=] of the [=entry point=].
     These denote the shader stage inputs.
  - The [=return value=] of the entry point.
     This denotes the shader stage outputs.
  - The [=uniform buffer=], [=storage buffer=], [=texture resource=], and [=sampler resource=] variables
        [=statically accessed=] by the shader.
  - The [=override-declarations=]
        [=statically accessed=] by the shader.

### Inter-stage Input and Output Interface ### {#stage-inputs-outputs}

A <dfn>shader stage input</dfn> is a datum provided to the shader stage from upstream in the pipeline.
Each datum is either a [=built-in input value=], or a [=user-defined input datum|user-defined input=].

A <dfn>shader stage output</dfn> is a datum the shader provides for further processing downstream in the pipeline.
Each datum is either a [=built-in output value=], or a [=user-defined output datum|user-defined output=].

[=IO attributes=] are used to establish an object as a [=shader stage input=] or a [=shader stage output=],
or to further describe the properties of an input or output.
The <dfn noexport>IO attributes</dfn> are:
* [=attribute/builtin=]
* [=attribute/location=]
* [=attribute/blend_src=]
* [=attribute/interpolate=]
* [=attribute/invariant=]

#### Built-in Inputs and Outputs #### {#builtin-inputs-outputs}

A <dfn noexport>built-in input value</dfn> provides access to system-generated control information.
An entry point [=shader-creation error|must=] not contain duplicated built-in inputs.

A built-in input for stage *S* with name *X* and type *T*<sub>*X*</sub> is accessed via a
[=formal parameter=] to an [=entry point=] for [=shader stage=] *S*, in one of two ways:

1. The parameter has attribute `builtin(`*X*`)` and is of type *T*<sub>*X*</sub>.
2. The parameter has structure type, where one of the structure members has attribute `builtin(`*X*`)` and is of type *T*<sub>*X*</sub>.

Conversely, when a parameter or member of a parameter for an entry point has a [=attribute/builtin=] attribute,
the corresponding builtin [=shader-creation error|must=] be an input for the entry point's shader stage.

A <dfn noexport>built-in output value</dfn> is used by the shader to convey
control information to later processing steps in the pipeline.
An entry point [=shader-creation error|must=] not contain duplicated built-in outputs.

A built-in output for stage *S* with name *Y* and type *T*<sub>*Y*</sub> is set via the [=return value=] for an
[=entry point=] for [=shader stage=] *S*, in one of two ways:

1. The entry point [=return type=] has attribute `builtin(`*Y*`)` and is of type *T*<sub>*Y*</sub>.
2. The entry point [=return type=] has structure type, where one of the structure members has attribute `builtin(`*Y*`)` and is of type *T*<sub>*Y*</sub>.

Conversely, when the return type or member of a return type for an entry point has a [=attribute/builtin=] attribute,
the corresponding builtin [=shader-creation error|must=] be an output for the entry point's shader stage.

Note: The [=built-in values/position=] built-in is both an output of a vertex shader, and an input to the fragment shader.

Collectively, built-in input and built-in output values are known as <dfn noexport>built-in values</dfn>.

The following table summarizes the available built-in values.
Each is a [=built-in value name-token|built-in value name=] [=token=] for a [=built-in value=].
Each is described in detail in subsequent sections.

<table class='data'>
  <caption>Built-in input and output values</caption>
  <thead>
    <tr><th>Name<th>Stage<th>Direction<th>Type
  </thead>

  <tr><td>[=built-in values/vertex_index=]
      <td>vertex
      <td>input
      <td>u32

  <tr><td>[=built-in values/instance_index=]
      <td>vertex
      <td>input
      <td>u32

  <tr><td>[=built-in values/clip_distances=]
      <td>vertex
      <td>output
      <td>array&lt;f32, N&gt; (`N` &le; `8`)

  <tr><td rowspan=2>[=built-in values/position=]
      <td>vertex
      <td>output
      <td>vec4&lt;f32&gt;

  <tr>
      <td>fragment
      <td>input
      <td>vec4&lt;f32&gt;

  <tr><td>[=built-in values/front_facing=]
      <td>fragment
      <td>input
      <td>bool

  <tr><td>[=built-in values/frag_depth=]
      <td>fragment
      <td>output
      <td>f32

  <tr><td>[=built-in values/sample_index=]
      <td>fragment
      <td>input
      <td>u32

  <tr><td rowspan=2>[=built-in values/sample_mask=]
      <td>fragment
      <td>input
      <td>u32

  <tr>
      <td>fragment
      <td>output
      <td>u32

  <tr><td>[=built-in values/local_invocation_id=]
      <td>compute
      <td>input
      <td>vec3&lt;u32&gt;

  <tr><td>[=built-in values/local_invocation_index=]
      <td>compute
      <td>input
      <td>u32

  <tr><td>[=built-in values/global_invocation_id=]
      <td>compute
      <td>input
      <td>vec3&lt;u32&gt;

  <tr><td>[=built-in values/workgroup_id=]
      <td>compute
      <td>input
      <td>vec3&lt;u32&gt;

  <tr><td>[=built-in values/num_workgroups=]
      <td>compute
      <td>input
      <td>vec3&lt;u32&gt;
</table>

<div class='example wgsl global-scope' heading="Declaring built-in values">
  <xmp highlight=wgsl>
    struct VertexOutput {
      @builtin(position) my_pos: vec4<f32>,
      @builtin(clip_distances) my_clip_distances: array<f32, 8>,
    }

    @vertex
    fn vs_main(
      @builtin(vertex_index) my_index: u32,
      @builtin(instance_index) my_inst_index: u32,
    ) -> VertexOutput {}

    struct FragmentOutput {
      @builtin(frag_depth) depth: f32,
      @builtin(sample_mask) mask_out: u32
    }

    @fragment
    fn fs_main(
      @builtin(front_facing) is_front: bool,
      @builtin(position) coord: vec4<f32>,
      @builtin(sample_index) my_sample_index: u32,
      @builtin(sample_mask) mask_in: u32,
    ) -> FragmentOutput {}

    @compute @workgroup_size(64)
    fn cs_main(
      @builtin(local_invocation_id) local_id: vec3<u32>,
      @builtin(local_invocation_index) local_index: u32,
      @builtin(global_invocation_id) global_id: vec3<u32>,
   ) {}
  </xmp>
</div>

##### `clip_distances` ##### {#clip-distances-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">clip_distances</dfn>
  <tr><td style="width:10%">Stage
      <td>[=vertex shader stage|vertex=]
  <tr><td style="width:10%">Type
      <td>array&lt;f32, N&gt;
  <tr><td style="width:10%">Direction
      <td>Output
  <tr><td style="width:10%">Description
      <td>
      Each value in the array represents a distance to a user-defined clip plane. A clip distance of
      `0` means the vertex is on the plane, a positive distance means the vertex is inside the clip
      half-space, and a negative distance means the vertex is outside the clip half-space. The array
      size of [=built-in values/clip_distances=] [=shader-creation error|must=] be &le; `8`.
      See [[WebGPU#primitive-clipping]].
</table>

##### `frag_depth` ##### {#frag-depth-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">frag_depth</dfn>
  <tr><td style="width:10%">Stage
      <td>[=fragment shader stage|fragment=]
  <tr><td style="width:10%">Type
      <td>f32
  <tr><td style="width:10%">Direction
      <td>Output
  <tr><td style="width:10%">Description
      <td>
      Updated depth of the fragment, in the viewport depth range.

      See [[WebGPU#coordinate-systems]].
</table>

##### `front_facing` ##### {#front-facing-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">front_facing</dfn>
  <tr><td style="width:10%">Stage
      <td>[=fragment shader stage|fragment=]
  <tr><td style="width:10%">Type
      <td>bool
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      True when the current fragment is on a [=front-facing=] primitive.
      False otherwise.
</table>

##### `global_invocation_id` ##### {#global-invocation-id-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">global_invocation_id</dfn>
  <tr><td style="width:10%">Stage
      <td>[=compute shader stage|compute=]
  <tr><td style="width:10%">Type
      <td>vec3&lt;u32&gt;
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      The current invocation's [=global invocation ID=], i.e. its position in
      the [=compute shader grid=]. The value of [=built-in values/global_invocation_id=]
      is equal to [=built-in values/workgroup_id=] * [=attribute/workgroup_size=] +
      [=built-in values/local_invocation_id=].

</table>

##### `instance_index` ##### {#instance-index-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">instance_index</dfn>
  <tr><td style="width:10%">Stage
      <td>[=vertex shader stage|vertex=]
  <tr><td style="width:10%">Type
      <td>u32
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      Instance index of the current vertex within the current API-level draw command.

      The first instance has an index equal to the `firstInstance` argument of the draw,
      whether provided directly or indirectly.
      The index is incremented by one for each additional instance in the draw.
</table>

##### `local_invocation_id` ##### {#local-invocation-id-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">local_invocation_id</dfn>
  <tr><td style="width:10%">Stage
      <td>[=compute shader stage|compute=]
  <tr><td style="width:10%">Type
      <td>vec3&lt;u32&gt;
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      The current invocation's [=local invocation ID=], i.e. its position in
      the [=workgroup grid=].
</table>

##### `local_invocation_index` ##### {#local-invocation-index-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">local_invocation_index</dfn>
  <tr><td style="width:10%">Stage
      <td>[=compute shader stage|compute=]
  <tr><td style="width:10%">Type
      <td>u32
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      The current invocation's [=local invocation index=], a linearized index of
      the invocation's position within the [=workgroup grid=].
</table>

##### `num_workgroups` ##### {#num-workgroups-index-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">num_workgroups</dfn>
  <tr><td style="width:10%">Stage
      <td>[=compute shader stage|compute=]
  <tr><td style="width:10%">Type
      <td>vec3&lt;u32&gt;
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      The [=dispatch size=], `vec3<u32>(group_count_x, group_count_y,
      group_count_z)`, of the compute shader
      [[WebGPU#compute-pass-encoder-dispatch|dispatched]] by the API.
</table>

##### `position` ##### {#position-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">position</dfn>
  <tr><td style="width:10%">Stage
      <td>[=vertex shader stage|vertex=]
  <tr><td style="width:10%">Type
      <td>vec4&lt;f32&gt;
  <tr><td style="width:10%">Direction
      <td>Output
  <tr><td style="width:10%">Description
      <td>
      The [=clip position=] of the current vertex,
      in [=clip space coordinates=].

      An output value (*x*,*y*,*z*,*w*)
      [=behavioral requirement|will=] map to (*x*/*w*, *y*/*w*, *z*/*w*) in
      WebGPU [=normalized device coordinates=].

      See [[WebGPU#coordinate-systems]] and [[WebGPU#primitive-clipping]].
</table>

<table class='data'>
  <tr><td style="width:10%">Name
      <td>position
  <tr><td style="width:10%">Stage
      <td>[=fragment shader stage|fragment=]
  <tr><td style="width:10%">Type
      <td>vec4&lt;f32&gt;
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      <div algorithm="fragment position calculation">
      Input position of the current fragment.

      Let |fp| be the input position of the fragment.<br>
      Let |rp| be the [=RasterizationPoint=] for the fragment.<br>
      Let |vp| be the {{RenderState/[[viewport]]}} in effect for the draw command.

      Then schematically:
      <blockquote>
      |fp|.xy = |rp|.[=rasterizationpoint-destination|destination=].[=fragmentdestination-position|position=]<br>
      |fp|.z = |rp|.[=rasterizationpoint-depth|depth=]<br>
      |fp|.w = |rp|.[=rasterizationpoint-perspectivedivisor|perspectiveDivisor=]
      </blockquote>

      In more detail:
      *  |fp|.x and |fp|.y are the interpolated x and y coordinates of the
          position the current fragment in
          the [=framebuffer=].

          The framebuffer is a two-dimensional grid of pixels with the top-left at (0.0,0.0)
          and the bottom right at (|vp|.width, |vp|.height).
          Each pixel has an extent of 1.0 unit in each of the x and y dimensions,
          and pixel centers are at (0.5,0.5) offset from integer coordinates.

      * |fp|.z is the interpolated depth of the current fragment.
          For example:
          * depth 0 in [=normalized device coordinates=] maps to |fp|.z = |vp|.minDepth,
          * depth 1 in normalized device coordinates maps to |fp|.z = |vp|.maxDepth.

      * |fp|.w is the perspective divisor for the fragment,
          which is the interpolation of 1.0 &divide; |vertex_w|,
          where |vertex_w| is the w component
          of the [=built-in values/position=] output of the vertex shader.

      See [[WebGPU#coordinate-systems]] and [[WebGPU#rasterization]].
      </div>
</table>

##### `sample_index` ##### {#sample-index-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">sample_index</dfn>
  <tr><td style="width:10%">Stage
      <td>[=fragment shader stage|fragment=]
  <tr><td style="width:10%">Type
      <td>u32
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      Sample index for the current fragment.  The value is least 0 and at most
      `sampleCount`-1, where `sampleCount` is the MSAA sample
      {{GPUMultisampleState/count}} specified for the GPU render pipeline.
      When this attribute is applied, if the effects of the fragment shader would vary based
      on the value of [=built-in values/sample_index=], the [=fragment=] shader will be invoked
      once per sample.

      See [[WebGPU#gpurenderpipeline]].
</table>

##### `sample_mask` ##### {#sample-mask-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">sample_mask</dfn>
  <tr><td style="width:10%">Stage
      <td>[=fragment shader stage|fragment=]
  <tr><td style="width:10%">Type
      <td>u32
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      Sample coverage mask for the current fragment.  It contains a bitmask
      indicating which samples in this fragment are covered by the primitive
      being rendered.

      See [[WebGPU#sample-masking]].
</table>

<table class='data'>
  <tr><td style="width:10%">Name
      <td>sample_mask
  <tr><td style="width:10%">Stage
      <td>[=fragment shader stage|fragment=]
  <tr><td style="width:10%">Type
      <td>u32
  <tr><td style="width:10%">Direction
      <td>Output
  <tr><td style="width:10%">Description
      <td>
      Sample coverage mask control for the current fragment.  The last value
      written to this variable becomes the [=shader-output mask=].  Zero bits
      in the written value will cause corresponding samples in the color
      attachments to be discarded.

      See [[WebGPU#sample-masking]].
</table>

##### `vertex_index` ##### {#vertex-index-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">vertex_index</dfn>
  <tr><td style="width:10%">Stage
      <td>[=vertex shader stage|vertex=]
  <tr><td style="width:10%">Type
      <td>u32
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      Index of the current vertex within the current API-level draw command,
      independent of draw instancing.

      For a non-indexed draw, the first vertex has an index equal to the `firstVertex` argument
      of the draw, whether provided directly or indirectly.
      The index is incremented by one for each additional vertex in the draw instance.

      For an indexed draw, the index is equal to the index buffer entry for the
      vertex, plus the `baseVertex` argument of the draw, whether provided directly or indirectly.
</table>

##### `workgroup_id` ##### {#workgroup-id-builtin-value}

<table class='data'>
  <tr><td style="width:10%">Name
      <td><dfn noexport dfn-for="built-in values">workgroup_id</dfn>
  <tr><td style="width:10%">Stage
      <td>[=compute shader stage|compute=]
  <tr><td style="width:10%">Type
      <td>vec3&lt;u32&gt;
  <tr><td style="width:10%">Direction
      <td>Input
  <tr><td style="width:10%">Description
      <td>
      The current invocation's [=workgroup ID=], i.e. the position of the
      workgroup in overall [=compute shader grid=].

      All invocations in the same workgroup have the same workgroup ID.

      Workgroup IDs span from (0,0,0) to ([=group_count_x=] - 1,
      [=group_count_y=] - 1, [=group_count_z=] - 1).
</table>

#### User-defined Inputs and Outputs #### {#user-defined-inputs-outputs}

User-defined data can be passed as input to the start of a pipeline, passed
between stages of a pipeline or output from the end of a pipeline.

Each <dfn noexport>user-defined input datum</dfn> and
<dfn noexport>user-defined output datum</abbrev></dfn> [=shader-creation error|must=]:
* be of [=numeric scalar=] type or [=numeric vector=] type.
* be assigned an IO location. See [[#input-output-locations]].


A [=compute=] shader [=shader-creation error|must not=] have user-defined inputs or outputs.

#### Input-output Locations #### {#input-output-locations}

Each input-output location can store a value up to 16 bytes in size.
The byte size of a type is defined using the *SizeOf* column in [[#alignment-and-size]].
For example, a four-component vector of floating-point values occupies a single location.

IO locations are specified via the [=attribute/location=] attribute.

Each user-defined [=user-defined input datum|input=] and [=user-defined output datum|output=] [=shader-creation error|must=] have an explicitly specified IO location.
Each structure member in the entry point IO [=shader-creation error|must=] be one of either a built-in value
(see [[#builtin-inputs-outputs]]), or assigned a location.


<div algorithm="locations in entry point inputs">
    For each entry point defined in a WGSL module, let |inputs| be its set of shader stage inputs
    (i.e. locations for its formal parameters, or for the members of its formal parameters of structure type).
    - |inputs| [=shader-creation error|must not=] contain two entries with the same [=attribute/location=] value.
</div>
<div algorithm="locations in structs">
    For each structure type |S| defined in a WGSL module (not just those used in shader stage inputs or outputs),
    let |members| be the set of members of |S| that have [=attribute/location=] attributes.
    - If any entry in |members| specifies a [=attribute/blend_src=] attribute:
        - |members| [=shader-creation error|must=] contain exactly `2` entries,
            one with `@location(0) @blend_src(0)` and one with `@location(0) @blend_src(1)`.
        - All the |members| [=shader-creation error|must=] have same data type.
    - Otherwise, |members| [=shader-creation error|must not=] contain two entries with the same [=attribute/location=] value.
</div>

Note: Location numbering is distinct between inputs and outputs:
Location numbers for an entry point's shader stage inputs do not conflict with location numbers for the entry point's shader stage outputs.

Note: No additional rule is required to prevent location overlap within an entry point's outputs.
When the output is a structure, the first rule above prevents overlap.
Otherwise, the output is a scalar or a vector, and can have only a single location assigned to it.

Note: The number of available locations for an entry point is defined by the WebGPU API.

<div class='example wgsl applying location attribute' heading='Applying location attributes'>
  <xmp highlight=wgsl>
    struct A {
      @location(0) x: f32,
      // Despite locations being 16-bytes, x and y cannot share a location
      @location(1) y: f32
    }

    // in1 occupies locations 0 and 1.
    // in2 occupies location 2.
    // The return value occupies location 0.
    @fragment
    fn fragShader(in1: A, @location(2) in2: f32) -> @location(0) vec4<f32> {
     // ...
    }
  </xmp>
</div>

User-defined IO can be mixed with built-in values in the same structure. For example,

<div class='example wgsl mixing builtins and user-defined IO' heading='Mixing builtins and user-defined IO'>
  <xmp highlight=wgsl>
    // Mixed builtins and user-defined inputs.
    struct MyInputs {
      @location(0) x: vec4<f32>,
      @builtin(front_facing) y: bool,
      @location(1) @interpolate(flat) z: u32
    }

    struct MyOutputs {
      @builtin(frag_depth) x: f32,
      @location(0) y: vec4<f32>
    }

    @fragment
    fn fragShader(in1: MyInputs) -> MyOutputs {
      // ...
    }
  </xmp>
</div>

<div class='example wgsl invalid locations' heading='Invalid location assignments'>
  <xmp highlight=wgsl>
    struct A {
      @location(0) x: f32,
      // Invalid, x and y cannot share a location.
      @location(0) y: f32
    }

    struct B {
      @location(0) x: f32
    }

    struct C {
      // Invalid, structures with user-defined IO cannot be nested.
      b: B
    }

    struct D {
      x: vec4<f32>
    }

    @fragment
    // Invalid, location cannot be applied to a structure type.
    fn fragShader1(@location(0) in1: D) {
      // ...
    }

    @fragment
    // Invalid, in1 and in2 cannot share a location.
    fn fragShader2(@location(0) in1: f32, @location(0) in2: f32) {
      // ...
    }

    @fragment
    // Invalid, location cannot be applied to a structure.
    fn fragShader3(@location(0) in1: vec4<f32>) -> @location(0) D {
      // ...
    }
  </xmp>
</div>

#### Interpolation #### {#interpolation}

Authors can control how user-defined IO data is interpolated through the use of
the [=attribute/interpolate=] attribute.
WGSL offers two aspects of interpolation to control: the type of
interpolation, and the sampling of the interpolation.

The <dfn export>interpolation type</dfn> [=shader-creation error|must=] be one of the following
[=interpolation type name-token|interpolation type name=] [=tokens=]:
: <dfn for="interpolation type" export>perspective</dfn>
:: Values are interpolated in a perspective correct manner.
: <dfn for="interpolation type" export>linear</dfn>
:: Values are interpolated in a linear, non-perspective correct manner.
: <dfn for="interpolation type" export>flat</dfn>
:: Values are not interpolated.

The <dfn export>interpolation sampling</dfn> [=shader-creation error|must=] be one of the following
[=interpolation sampling name-token|interpolation sampling name=] [=tokens=]:
: <dfn for="interpolation sampling" export>center</dfn>
:: Interpolation is performed at the center of the pixel.
: <dfn for="interpolation sampling" export>centroid</dfn>
:: Interpolation is performed at a point that lies within all the
    samples covered by the fragment within the current primitive.
    This value is the same for all samples in the primitive.
: <dfn for="interpolation sampling" export>sample</dfn>
:: Interpolation is performed per sample.
    The [=fragment=] shader is invoked once per sample when this attribute is
    applied.
: <dfn for="interpolation sampling" export>first</dfn>
:: The value is provided by the first vertex of the primitive.
: <dfn for="interpolation sampling" export>either</dfn>
:: The value is provided by the first vertex or last vertex of the primitive.
    Whether the value comes from the first or last vertex is implementation dependent.

For user-defined IO of scalar or vector floating-point type:
* If the interpolation attribute is not specified, then `@interpolate(perspective, center)` is assumed.
* If the interpolation attribute is specified with an interpolation type:
    * If the interpolation type is `flat`, then:
        * If interpolation sampling is specified, it [=shader-creation error|must=] be `first` or `either`.
        * Otherwise, `first` is assumed.
    * If the interpolation type is `perspective` or `linear`, then:
        * If interpolation sampling is specified, it [=shader-creation error|must=] be `center`, `centroid`, or `sample`.
        * Otherwise, `center` is assumed.

User-defined [=vertex=] outputs and [=fragment=] inputs of scalar or vector
integer type [=shader-creation error|must=] always be specified with interpolation type `flat`.

Interpolation attributes [=shader-creation error|must=] match between [=vertex=] outputs and [=fragment=]
inputs with the same [=attribute/location=] assignment within the same [=pipeline=].


### Resource Interface ### {#resource-interface}

A <dfn noexport>resource</dfn> is an object which provides access to data external to a [=shader stage=],
and which is not an [=override-declaration=] and not a [[#stage-inputs-outputs|shader stage input or output]].
Resources are shared by all invocations of the shader.

There are four kinds of resources:

* [=Uniform buffers=]
* [=Storage buffers=]
* [=Texture resources=]
* [=Sampler resources=]

The <dfn noexport>resource interface of a shader</dfn> is the set of module-scope
resource variables [=statically accessed=] by
[=functions in a shader stage|functions in the shader stage=].

Each resource variable [=shader-creation error|must=] be declared with both [=attribute/group=] and [=attribute/binding=]
attributes.
Together with the shader's stage, these identify the binding address
of the resource on the shader's pipeline.
See [[WebGPU#gpupipelinelayout]].

Two different resource variables in a [=shader=] [=shader-creation error|must
not=] have the same [=attribute/group=] and [=attribute/binding=] values, when
considered as a pair.

### Resource Layout Compatibility ### {#resource-layout-compatibility}

WebGPU requires that a shader's resource interface match the [[WebGPU#gpupipelinelayout|layout of the pipeline]]
using the shader.

It is a [=pipeline-creation error=] if a WGSL variable in a resource interface is bound to an incompatible WebGPU
[=binding resource type=] or [=binding type=],
where compatibility is defined by the following table.
<table class='data'>
  <caption>WebGPU binding type compatibility</caption>
  <thead>
    <tr><th>WGSL resource
        <th>WebGPU<br>[=binding resource type|resource type=]
        <th>WebGPU [=binding member=]
        <th colspan=2>WebGPU [=binding type=]
  </thead>
  <tr><td>[=uniform buffer=]
      <td rowspan=3>{{GPUBufferBinding}}
      <td rowspan=3>{{GPUBindGroupLayoutEntry/buffer}}
      <td rowspan=3>GPUBufferBindingType
      <td>{{GPUBufferBindingType/"uniform"}}
  <tr><td>[=storage buffer=] with [=access/read_write=] access
      <td>{{GPUBufferBindingType/"storage"}}
  <tr><td>[=storage buffer=] with [=access/read=] access
      <td>{{GPUBufferBindingType/"read-only-storage"}}
  <tr><td rowspan=2>[=type/sampler=]
      <td rowspan=3>{{GPUSampler}}
      <td rowspan=3>{{GPUBindGroupLayoutEntry/sampler}}
      <td rowspan=3>GPUSamplerBindingType
      <td>{{GPUSamplerBindingType/"filtering"}}
  <tr>
      <td>{{GPUSamplerBindingType/"non-filtering"}}
  <tr><td>[=type/sampler_comparison=]
      <td>{{GPUSamplerBindingType/"comparison"}}
  <tr><td rowspan=5>[=type/sampled texture=],
                    [=type/depth texture=], or
                    [=type/multisampled texture=]
      <td rowspan=5>{{GPUTextureView}}
      <td rowspan=5>{{GPUBindGroupLayoutEntry/texture}}
      <td rowspan=5>GPUTextureSampleType
      <td>{{GPUTextureSampleType/"float"}}
  <tr>
      <td>{{GPUTextureSampleType/"unfilterable-float"}}
  <tr>
      <td>{{GPUTextureSampleType/"sint"}}
  <tr>
      <td>{{GPUTextureSampleType/"uint"}}
  <tr>
      <td>{{GPUTextureSampleType/"depth"}}
  <tr><td>[=type/write-only storage texture=]
      <td rowspan=3>{{GPUTextureView}}
      <td rowspan=3>{{GPUBindGroupLayoutEntry/storageTexture}}
      <td rowspan=3>{{GPUStorageTextureAccess}}
      <td>{{GPUStorageTextureAccess/"write-only"}}
  <tr><td>[=type/read-write storage texture=]
      <td>{{GPUStorageTextureAccess/"read-write"}}
  <tr><td>[=type/read-only storage texture=]
      <td>{{GPUStorageTextureAccess/"read-only"}}
  <tr><td>[=type/external texture=]
      <td>{{GPUExternalTexture}}
      <td>{{GPUBindGroupLayoutEntry/externalTexture}}
      <td colspan=2>(not applicable)
</table>

See the [$validating GPUProgrammableStage|WebGPU API$]
specification for interface validation requirements.

### Buffer Binding Determines Runtime-Sized Array Element Count ### {#buffer-binding-determines-runtime-sized-array-element-count}

When a [=storage buffer=] variable contains a [=runtime-sized=] array, then the number of elements in that array
is determined from the size of the corresponding {{GPUBufferBinding}}:

<blockquote algorithm="element count of runtime-sized array">
* Let |T| be the [=store type=] for a [=storage buffer=] variable,
    where |T| is a [=runtime-sized=] array type or contains a runtime-sized array type.
* Let |EBS| be the
    [=effective buffer binding size=]
    for the {{GPUBufferBinding}} bound to the pipeline binding address corresponding to the storage buffer variable.
* Then <dfn noexport>NRuntime</sub></dfn>, i.e.
    the number of elements in the runtime-sized array,
    is the largest integer such that [=SizeOf=](|T|) &le; |EBS|.

</blockquote>

In more detail, the [=NRuntime=] for a runtime-size array of type *RAT* is:
<blockquote algorithm="element count of runtime-sized array, expanded">
[=truncate=]((EBBS &minus; *array_offset*) &divide; *array_stride*), where:
* EBBS is the [=effective buffer binding size=] associated with the variable,
* *array_offset* is the byte offset of the runtime-sized array within the store type of the variable.
    * It is zero if the store type is |RAT|, the runtime-sized array type itself.
    * Otherwise the store type is a structure, and its last member is the runtime-sized array.
        In this case *array_offset* is the [=OffsetOfMember|byte offset of that member=] within the structure.
* *array_stride* is the stride of the array type, i.e. [=StrideOf=](|RAT|).

</blockquote>

A shader can compute [=NRuntime=] via the [[#arrayLength-builtin|arrayLength]] builtin function.

<div class=note>
<span class=marker>Note:</span>
This algorithm is unambiguous:
When a runtime-sized array is part of a larger type, it may only appear as the last element of a structure,
which itself cannot be part of an enclosing array or structure.

[=NRuntime=] is determined by the size of the corresponding buffer binding, and that can be different for each [=draw command|draw=]
or [=dispatch command=].

WebGPU validation rules ensure that 1 &le; [=NRuntime=].

</div>


<div class=note>
In the following code sample:
* The `weights` variable is a [=storage buffer=].
* Its store type is the runtime-sized arry type `array<f32>`.
* The array offset is 0.
* The array stride is [=StrideOf=](array&lt;f32&gt;), which is 4.

<div class='example wgsl' heading='number of elements in a simple runtime sized array'>
  <xmp highlight=wgsl>
@group(0) @binding(1) var<storage> weights: array<f32>;
  </xmp>
</div>

The following table shows examples of [=NRuntime=] for the `weights` variable, based on
the corresponding effective buffer binding size.

<table class='data'>
  <caption>Example number of elements for simple runtime-sized array</caption>
  <thead>
    <tr><th style="width:15%">Effective buffer binding size<th>NRuntime for `weights` variable<td>Calculation
  </thead>
  <tr><td>1024<td>256<td>[=truncate=]( 1024 &divide; 4 )
  <tr><td>1025<td>256<td>[=truncate=]( 1025 &divide; 4 )
  <tr><td>1026<td>256<td>[=truncate=]( 1026 &divide; 4 )
  <tr><td>1027<td>256<td>[=truncate=]( 1027 &divide; 4 )
  <tr><td>1028<td>257<td>[=truncate=]( 1028 &divide; 4 )
</table>
</div>

<div class=note>
In the following code sample:
* The `lights` variable is a [=storage buffer=].
* Its store type is `LightStorage`.
* The `point` member of `LightStorage` is a runtime-sized array of type `array<PointLight>`.
    * The member is at byte offset 16 in the variable's storage.
    * The array stride is [=StrideOf=](array&lt;`PointLight`&gt;) = [=roundUp=]([=AlignOf=](`PointLight`),[=SizeOf=](`PointLight`)) = [=roundUp=](16,32) = 32

<div class='example wgsl' heading='number of elements in a complex runtime sized array'>
  <xmp highlight=wgsl>
struct PointLight {                          //             align(16) size(32)
  position : vec3f,                          // offset(0)   align(16) size(12)
  // -- implicit member alignment padding -- // offset(12)            size(4)
  color : vec3f,                             // offset(16)  align(16) size(12)
  // -- implicit struct size padding --      // offset(28)            size(4)
}

struct LightStorage {                        //             align(16)
  pointCount : u32,                          // offset(0)   align(4)  size(4)
  // -- implicit member alignment padding -- // offset(4)             size(12)
  point : array<PointLight>,                 // offset(16)  align(16) elementsize(32)
}

@group(0) @binding(1) var<storage> lights : LightStorage;
  </xmp>
</div>

The following table shows examples of [=NRuntime=] for the `point` member of the `lights` variable.

<table class='data'>
  <caption>Example number of elements for complex runtime-sized array</caption>
  <thead>
    <tr><th style="width:15%">Effective buffer binding size<th>NRuntime for `point` member of `lights` variable<td>Calculation
  </thead>
  <tr><td>1024<td>31<td>[=truncate=]( ( 1024 - 16 ) &divide; 32) )
  <tr><td>1025<td>31<td>[=truncate=]( ( 1025 - 16 ) &divide; 32) )
  <tr><td>1039<td>31<td>[=truncate=]( ( 1039 - 16 ) &divide; 32) )
  <tr><td>1040<td>32<td>[=truncate=]( ( 1040 - 16 ) &divide; 32) )
  </thead>
</table>
</div>

# Memory # {#memory}

In WGSL, a value of [=storable=] type may be stored in memory, for later retrieval.
This section describes the structure of memory, and the semantics of operations accessing memory.
See [[#memory-views]] for the types of values that can be placed in memory, and the types used to perform memory accesses.

## Memory Locations ## {#memory-locations-section}

Memory consists of a set of distinct <dfn noexport>memory locations</dfn>.
Each memory location is 8-bits in size.
An operation affecting memory interacts with a set of one or more memory locations.
Memory operations on [=composites=] [=behavioral requirement|will not=]
access padding memory locations.
Therefore, the set of memory locations accessed by an operation may not be contiguous.

Two sets of memory locations <dfn noexport>overlap</dfn> if the intersection of
their sets of memory locations is non-empty.

## Memory Access Mode ## {#memory-access-mode}

A <dfn noexport>memory access</dfn> is an operation that acts on [=memory locations=].

* A <dfn noexport>read access</dfn> observes the contents of memory locations.
* A <dfn noexport>write access</dfn> sets the contents of memory locations.

A single operation can read, write, or both read and write.

Particular memory locations may support only certain kinds of accesses, expressed
as the memory's <dfn noexport>access mode</dfn>.

<table class='data'>
  <caption>Access Modes</caption>
  <thead>
    <tr><th>Access mode
        <th>Supported accesses
  </thead>
  <tr><td><dfn noexport dfn-for="access">read</dfn>
      <td>Supports read accesses, but not writes.
  <tr><td><dfn noexport dfn-for="access">write</dfn>
      <td>Supports write accesses, but not reads.
  <tr><td><dfn noexport dfn-for="access">read_write</dfn>
      <td>Supports both read and write accesses.
</table>

WGSL [=predeclared|predeclares=] the [=enumerants=] `read`, `write`, and `read_write`.

## Address Spaces ## {#address-space}

Memory locations are partitioned into <dfn noexport>address spaces</dfn>.
Each address space has unique properties determining
mutability, visibility, the values it may contain,
and how to use variables with it.
See [[#var-and-value]] for more details.

The access mode of a given [=memory view=] is often determined by context:

The [=address spaces/storage=] address spaces supports both [=access/read=] and
[=access/read_write=] access modes.
Each other address space supports only one access mode.
The default access mode for each address space is described in the following
table.

<table class='data'>
  <caption>Address Spaces</caption>
  <thead>
    <tr><th>Address space
        <th>Sharing among invocations
        <th>Default access mode
        <th>Notes
  </thead>
  <tr><td><dfn noexport dfn-for="address spaces">function</dfn>
      <td>Same invocation only
      <td>[=access/read_write=]
      <td>
  <tr><td><dfn noexport dfn-for="address spaces">private</dfn>
      <td>Same invocation only
      <td>[=access/read_write=]
      <td>
  <tr><td><dfn noexport dfn-for="address spaces">workgroup</dfn>
      <td>Invocations in the same [=compute shader stage|compute shader=] [=compute shader stage/workgroup=]
      <td>[=access/read_write=]
      <td>The [=element count=] of an outermost array may be a [=pipeline-overridable=] constant.
  <tr><td><dfn noexport dfn-for="address spaces">uniform</dfn>
      <td>Invocations in the same [=shader stage=]
      <td>[=access/read=]
      <td>For [=uniform buffer=] variables
  <tr><td><dfn noexport dfn-for="address spaces">storage</dfn>
      <td>Invocations in the same [=shader stage=]
      <td>[=access/read=]
      <td>For [=storage buffer=] variables
  <tr><td><dfn noexport dfn-for="address spaces">handle</dfn>
      <td>Invocations in the same shader stage
      <td>[=access/read=]
      <td>For [=sampler resource|sampler=] and [=texture resource|texture=] variables.<br>
</table>

WGSL [=predeclared|predeclares=] an [=enumerant=] for each address space, except for the `handle` address space.

[=Variables=] in the [=address spaces/workgroup=] address space
[=shader-creation error|must=] only be [=statically accessed=] in a [=compute
shader stage=].

[=Variables=] in the [=address spaces/storage=] address space ([=storage
buffers=]) can only be [=statically accessed=] by a [=vertex shader stage=] if the access mode is [=access/read=].
Variables whose [=store type=] is a [=type/storage texture=] with a
[=access/write=] or [=access/read_write=] [=access mode=] cannot be
[=statically accessed=] by a [=vertex shader stage=].
See WebGPU {{GPUDevice/createBindGroupLayout()}}.

Note: Each address space may have different performance characteristics.

When writing a [=variable declaration=] or a [=pointer type=] in WGSL source:
* For the [=address spaces/storage=] address space, the access mode is optional, and defaults to [=access/read=].
* For other address spaces, the access mode [=shader-creation error|must not=] be written.

## Memory Layout ## {#memory-layouts}

The layout of types in WGSL is independent of [=address space=].
Strictly speaking, however, that layout can only be observed by host-shareable
buffers.
[=Uniform buffer=] and [=storage buffer=] variables are used to share
bulk data organized as a sequence of bytes in memory.
Buffers are shared between the CPU and the GPU, or between different shader stages
in a pipeline, or between different pipelines.

Because buffer data are shared without reformatting or translation, it is a
[=dynamic error=] if buffer producers and consumers do not agree on the <dfn
noexport>memory layout</dfn>, which is the description of how the bytes in a
buffer are organized into typed WGSL values.
These bytes are [=memory locations=] of a value relative to a common base
location.

The [=store type=] of a buffer variable [=shader-creation error|must=] be
[=host-shareable=], with fully elaborated memory layout, as described below.

Each buffer variable [=shader-creation error|must=] be declared in either the
[=address spaces/uniform=] or [=address spaces/storage=] address spaces.

The memory layout of a type is significant only when evaluating an expression with:
* a variable in the [=address spaces/uniform=] or [=address spaces/storage=] address space, or
* a pointer into the [=address spaces/uniform=] or [=address spaces/storage=] address space.

An 8-bit byte is the most basic unit of [=host-shareable=] memory.
The terms defined in this section express counts of 8-bit bytes.

We will use the following notation:
* <dfn noexport>AlignOf</dfn>(|T|) is the [=alignment=] of host-shareable type |T|.
* <dfn noexport>AlignOfMember</dfn>(|S|, |i|) is the alignment of the |i|'th member of the host-shareable structure |S|.
* <dfn noexport>SizeOf</dfn>(|T|) is the [=byte-size=] of host-shareable type |T|.
* <dfn noexport>SizeOfMember</dfn>(|S|, |i|) is the size of the |i|'th member of the host-shareable structure |S|.
* <dfn noexport>OffsetOfMember</dfn>(|S|, |i|) is the offset of the |i|'th member from the start of the host-shareable structure |S|.
* <dfn noexport>StrideOf</dfn>(|A|) is the <dfn>element stride</dfn> of host-shareable array type |A|, defined
    as the number of bytes from the start of one array element to the start of the next element.
    It equals the size of the array's element type, rounded up to the alignment of the element type:
        <p algorithm="array element stride">
          [=StrideOf=](array<|E|, |N|>) = [=roundUp=]([=AlignOf=](E), [=SizeOf=](E))<br>
          [=StrideOf=](array<|E|>) = [=roundUp=]([=AlignOf=](E), [=SizeOf=](E))
        </p>

### Alignment and Size ###  {#alignment-and-size}

Each [=host-shareable=] or [=fixed footprint=] data type |T| has an alignment and size.

The <dfn>alignment</dfn> of a type is a constraint on where values of that type
may be placed in memory, expressed as an integer:
a type's alignment [=shader-creation error|must=] evenly divide
the byte address of the starting [=memory location=] of a value of that type.
Alignments enable use of more efficient hardware instructions for accessing the values,
or satisfy more restrictive hardware requirements on certain
address spaces. (See [address space layout constraints](#address-space-layout-constraints)).

Note: Each alignment value is always a power of two, by construction.

The <dfn>byte-size</dfn> of a type or structure member is the number of contiguous bytes
reserved in host-shareable memory for the purpose of storing a value of the type
or structure member.
The size may include non-addressable padding at the end of the type.
Consequently, loads and stores of a value might access fewer memory locations
than the value's size.

Alignment and size of [=host-shareable=] types are defined recursively in the
following table:

<table class='data'>
  <caption>
    Alignment and size for host-shareable types<br>
  </caption>
  <thead>
    <tr><th>Host-shareable type |T|
        <th>[=AlignOf=](|T|)
        <th>[=SizeOf=](|T|)
  </thead>
  <tr><td>[=i32=], [=u32=], or [=f32=]
      <td>4
      <td>4
  <tr><td>[=f16=]
      <td>2
      <td>2
  <tr><td>[=atomic type|atomic&lt;|T|&gt;=]
      <td>4
      <td>4
  <tr><td>[=vector|vec=]2&lt;|T|&gt;, |T| is [=i32=], [=u32=], or [=f32=]
      <td>8
      <td>8
  <tr><td>vec2&lt;f16&gt;
      <td>4
      <td>4
  <tr><td>vec3&lt;|T|&gt;, |T| is [=i32=], [=u32=], or [=f32=]
      <td>16
      <td>12
  <tr><td>vec3&lt;f16&gt;
      <td>8
      <td>6
  <tr><td>vec4&lt;|T|&gt;, |T| is [=i32=], [=u32=], or [=f32=]
      <td>16
      <td>16
  <tr><td>vec4&lt;f16&gt;
      <td>8
      <td>8
  <tr><td>[=matrix|mat=]|C|x|R| (col-major)<br>
      <p class="small">(General form)</p>
      <td>[=AlignOf=](vec|R|)
      <td>[=SizeOf=](array&lt;vec|R|, |C|&gt;)
  <tr><td>mat2x2&lt;f32&gt;
      <td>8
      <td>16
  <tr><td>mat2x2&lt;f16&gt;
      <td>4
      <td>8
  <tr><td>mat3x2&lt;f32&gt;
      <td>8
      <td>24
  <tr><td>mat3x2&lt;f16&gt;
      <td>4
      <td>12
  <tr><td>mat4x2&lt;f32&gt;
      <td>8
      <td>32
  <tr><td>mat4x2&lt;f16&gt;
      <td>4
      <td>16
  <tr><td>mat2x3&lt;f32&gt;
      <td>16
      <td>32
  <tr><td>mat2x3&lt;f16&gt;
      <td>8
      <td>16
  <tr><td>mat3x3&lt;f32&gt;
      <td>16
      <td>48
  <tr><td>mat3x3&lt;f16&gt;
      <td>8
      <td>24
  <tr><td>mat4x3&lt;f32&gt;
      <td>16
      <td>64
  <tr><td>mat4x3&lt;f16&gt;
      <td>8
      <td>32
  <tr><td>mat2x4&lt;f32&gt;
      <td>16
      <td>32
  <tr><td>mat2x4&lt;f16&gt;
      <td>8
      <td>16
  <tr><td>mat3x4&lt;f32&gt;
      <td>16
      <td>48
  <tr><td>mat3x4&lt;f16&gt;
      <td>8
      <td>24
  <tr><td>mat4x4&lt;f32&gt;
      <td>16
      <td>64
  <tr><td>mat4x4&lt;f16&gt;
      <td>8
      <td>32
  <tr><td>[=structure|struct=] |S| with members M<sub>1</sub>...M<sub>N</sub>
      <td>max([=AlignOfMember=](S,1), ... , [=AlignOfMember=](S,N))<br>
      <td>[=roundUp=]([=AlignOf=](|S|), justPastLastMember)<br><br>
          where justPastLastMember = [=OffsetOfMember=](|S|,N) + [=SizeOfMember=](|S|,N)
  <tr><td>[=array=]<|E|, |N|><br>
      <td>[=AlignOf=](|E|)
      <td>|N| &times; [=roundUp=]([=AlignOf=](|E|), [=SizeOf=](|E|))
  <tr><td>array<|E|><br>
      <td>[=AlignOf=](|E|)
      <td>[=NRuntime=] &times; [=roundUp=]([=AlignOf=](|E|),[=SizeOf=](|E|))<br><br>
          where NRuntime is the runtime-determined number of elements of |T|
</table>

### Structure Member Layout ###  {#structure-member-layout}

The internal layout of a [=structure=] is computed from the sizes and alignments of its members.
By default, the members are arranged tightly, in order, without overlap, while satisfying member alignment
requirements.

This default internal layout can be overriden by using <dfn noexport>layout attributes</dfn>, which are:

* [=attribute/size=]
* [=attribute/align=]

The |i|'th member of structure type |S| has a size and alignment, denoted
by [=SizeOfMember=](|S|, |i|) and [=AlignOfMember=](|S|, |i|), respectively.
The member sizes and alignments are used to calculate each member's byte offset from the start of the structure,
as described in [[#internal-value-layout]].

<p algorithm="structure member size">
  [=SizeOfMember=](|S|, |i|) is |k| if the |i|'th member of |S| has attribute [=attribute/size=](|k|).
  Otherwise, it is [=SizeOf=](|T|) where |T| is the type of the member.
</p>

<p algorithm="structure member alignment">
  [=AlignOfMember=](|S|, |i|) is |k| if the |i|'th member of |S| has attribute [=attribute/align=](|k|).
  Otherwise, it is [=AlignOf=](|T|) where |T| is the type of the member.
</p>

If a structure member has the [=attribute/size=] attribute applied, the
value [=shader-creation error|must=] be at least as large as the size of the
member's type:

<p algorithm="member size constraint">
  [=SizeOfMember=](|S|, |i|) &ge; [=SizeOf=](T)<br>
  Where |T| is the type of the |i|'th member of |S|.
</p>

The first structure member always has a zero byte offset from the start of the
structure:
<p algorithm="offset of first structure member">
  [=OffsetOfMember=](<var ignore>S</var>, 1) = 0
</p>

Each subsequent member is placed at the lowest offset that satisfies the member type alignment,
and which avoids overlap with the previous member.
For each member index |i| > 1:
<p algorithm="structure member offset">
  [=OffsetOfMember=](|S|, |i|) = [=roundUp=]([=AlignOfMember=](|S|, |i| ), [=OffsetOfMember=](|S|, |i|-1) + [=SizeOfMember=](|S|, |i|-1))<br>
</p>

<div class='example wgsl' heading='Layout of structures using implicit member sizes and alignments'>
  <xmp highlight=wgsl>
    struct A {                                     //             align(8)  size(24)
        u: f32,                                    // offset(0)   align(4)  size(4)
        v: f32,                                    // offset(4)   align(4)  size(4)
        w: vec2<f32>,                              // offset(8)   align(8)  size(8)
        x: f32                                     // offset(16)  align(4)  size(4)
        // -- implicit struct size padding --      // offset(20)            size(4)
    }

    struct B {                                     //             align(16) size(160)
        a: vec2<f32>,                              // offset(0)   align(8)  size(8)
        // -- implicit member alignment padding -- // offset(8)             size(8)
        b: vec3<f32>,                              // offset(16)  align(16) size(12)
        c: f32,                                    // offset(28)  align(4)  size(4)
        d: f32,                                    // offset(32)  align(4)  size(4)
        // -- implicit member alignment padding -- // offset(36)            size(4)
        e: A,                                      // offset(40)  align(8)  size(24)
        f: vec3<f32>,                              // offset(64)  align(16) size(12)
        // -- implicit member alignment padding -- // offset(76)            size(4)
        g: array<A, 3>,    // element stride 24       offset(80)  align(8)  size(72)
        h: i32                                     // offset(152) align(4)  size(4)
        // -- implicit struct size padding --      // offset(156)           size(4)
    }

    @group(0) @binding(0)
    var<storage,read_write> storage_buffer: B;
  </xmp>
</div>

<div class='example wgsl' heading='Layout of structures with explicit member sizes and alignments'>
  <xmp highlight=wgsl>
    struct A {                                     //             align(8)  size(32)
        u: f32,                                    // offset(0)   align(4)  size(4)
        v: f32,                                    // offset(4)   align(4)  size(4)
        w: vec2<f32>,                              // offset(8)   align(8)  size(8)
        @size(16) x: f32                           // offset(16)  align(4)  size(16)
    }

    struct B {                                     //             align(16) size(208)
        a: vec2<f32>,                              // offset(0)   align(8)  size(8)
        // -- implicit member alignment padding -- // offset(8)             size(8)
        b: vec3<f32>,                              // offset(16)  align(16) size(12)
        c: f32,                                    // offset(28)  align(4)  size(4)
        d: f32,                                    // offset(32)  align(4)  size(4)
        // -- implicit member alignment padding -- // offset(36)            size(12)
        @align(16) e: A,                           // offset(48)  align(16) size(32)
        f: vec3<f32>,                              // offset(80)  align(16) size(12)
        // -- implicit member alignment padding -- // offset(92)            size(4)
        g: array<A, 3>,    // element stride 32       offset(96)  align(8)  size(96)
        h: i32                                     // offset(192) align(4)  size(4)
        // -- implicit struct size padding --      // offset(196)           size(12)
    }

    @group(0) @binding(0)
    var<uniform> uniform_buffer: B;
  </xmp>
</div>

### Array Layout Examples ###  {#array-layout-examples}

<div class='example wgsl function-scope' heading='Fixed-size array layout examples'>
  <xmp highlight=wgsl>
    // Array where:
    //   - alignment is 4 = AlignOf(f32)
    //   - element stride is 4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4)
    //   - size is 32 = stride * number_of_elements = 4 * 8
    var small_stride: array<f32, 8>;

    // Array where:
    //   - alignment is 16 = AlignOf(vec3<f32>) = 16
    //   - element stride is 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>))
    //                          = roundUp(16,12)
    //   - size is 128 = stride * number_of_elements = 16 * 8
    var bigger_stride: array<vec3<f32>, 8>;
  </xmp>
</div>

<div class='example wgsl global-scope' heading='Runtime-sized array layout examples'>
  <xmp highlight=wgsl>
    // Array where:
    //   - alignment is 4 = AlignOf(f32)
    //   - element stride is 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4
    // If B is the effective buffer binding size for the binding on the
    // draw or dispatch command, the number of elements is:
    //   N_runtime = floor(B / element stride) = floor(B / 4)
    @group(0) @binding(0)
    var<storage> weights: array<f32>;

    // Array where:
    //   - alignment is 16 = AlignOf(vec3<f32>) = 16
    //   - element stride is 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>))
    //                          = roundUp(16,12)
    // If B is the effective buffer binding size for the binding on the
    // draw or dispatch command, the number of elements is:
    //   N_runtime = floor(B / element stride) = floor(B / 16)
    var<storage> directions: array<vec3<f32>>;
  </xmp>
</div>

### Internal Layout of Values ###  {#internal-value-layout}

This section describes how the internals of a value are placed in the byte locations
of a buffer, given an assumed placement of the overall value.
These layouts depend on the value's type,
and the [=attribute/align=] and [=attribute/size=] attributes on structure members.

The buffer byte offset at which a value is placed [=shader-creation
error|must=] satisfy the type alignment requirement: If a value of type |T| is
placed at buffer offset |k|, then |k| = |c| &times; [=AlignOf=](|T|), for some
non-negative integer |c|.

The data [=behavioral requirement|will=] appear identically regardless of the address space.

When a value |V| of type [=u32=] or [=i32=] is placed at byte offset |k| of a
host-shared buffer, then:
   * Byte |k| contains bits 0 through 7 of |V|
   * Byte |k|+1 contains bits 8 through 15 of |V|
   * Byte |k|+2 contains bits 16 through 23 of |V|
   * Byte |k|+3 contains bits 24 through 31 of |V|

Note: Recall that [=i32=] uses twos-complement representation, so the sign bit
is in bit position 31.

<dfn>64-bit integer</dfn> layout: Some features of the WebGPU API write 64-bit
unsigned integer values into buffers. When such a value |V| appears at byte
offset |k| of a host-shared buffer, then:
   * Byte |k| contains bits 0 through 7 of |V|
   * Byte |k|+1 contains bits 8 through 15 of |V|
   * Byte |k|+2 contains bits 16 through 23 of |V|
   * Byte |k|+3 contains bits 24 through 31 of |V|
   * Byte |k|+4 contains bits 32 through 39 of |V|
   * Byte |k|+5 contains bits 40 through 47 of |V|
   * Byte |k|+6 contains bits 48 through 55 of |V|
   * Byte |k|+7 contains bits 56 through 63 of |V|

Note: WGSL does not have a [=type/concrete=] [=64-bit integer=] type.

A value |V| of type [=f32=] is represented in [[!IEEE-754|IEEE-754]] binary32 format.
It has one sign bit, 8 exponent bits, and 23 fraction bits.
When |V| is placed at byte offset |k| of host-shared buffer, then:
   * Byte |k| contains bits 0 through 7 of the fraction.
   * Byte |k|+1 contains bits 8 through 15 of the fraction.
   * Bits 0 through 6 of byte |k|+2 contain bits 16 through 22 of the fraction.
   * Bit 7 of byte |k|+2 contains bit 0 of the exponent.
   * Bits 0 through 6 of byte |k|+3 contain bits 1 through 7 of the exponent.
   * Bit 7 of byte |k|+3 contains the sign bit.

A value |V| of type [=f16=] is represented in [[!IEEE-754|IEEE-754]] binary16 format.
It has one sign bit, 5 exponent bits, and 10 fraction bits.
When |V| is placed at byte offset |k| of host-shared buffer, then:
   * Byte |k| contains bits 0 through 7 of the fraction.
   * Bits 0 through 1 of byte |k|+1 contain bits 8 through 9 of the fraction.
   * Bits 2 through 6 of byte |k|+1 contain bits 0 through 4 of the exponent.
   * Bit 7 of byte |k|+1 contains the sign bit.

Note: The above rules imply that numeric values in host-shared buffers
are stored in little-endian format.

When a value |V| of [=atomic type=] `atomic`&lt;|T|&gt; is placed in a host-shared buffer,
it has the same internal layout as a value of the underlying type |T|.

When a value |V| of [=vector|vector type=] vec|N|&lt;|T|&gt; is placed at
byte offset |k| of a host-shared buffer, then:
   * |V|.x is placed at byte offset |k|
   * |V|.y is placed at byte offset |k| + [=SizeOf=](|T|)
   * If |N| &ge; 3, then |V|.z is placed at byte offset |k| + 2 &times; [=SizeOf=](|T|)
   * If |N| &ge; 4, then |V|.w is placed at byte offset |k| + 3 &times; [=SizeOf=](|T|)

When a value |V| of [=matrix|matrix type=] mat|C|x|R|&lt;|T|&gt; is placed at
byte offset |k| of a host-shared buffer, then:
  * Column vector |i| of |V| is placed at byte offset |k| + |i| &times; [=AlignOf=](vec|R|&lt;|T|&gt;)

When a value of [=array|array type=] |A| is placed at byte offset |k| of a host-shared memory buffer,
then:
   * Element |i| of the array is placed at byte offset |k| + |i| &times; [=StrideOf=](|A|)

When a value of [=structure|structure type=] |S| is placed at byte offset |k| of a host-shared memory buffer,
then:
   * The |i|'<sup>th</sup> member of the structure value is placed at byte offset |k| + [=OffsetOfMember=](|S|,|i|).
    See [[#structure-member-layout]].

### Address Space Layout Constraints ###  {#address-space-layout-constraints}

The [=address spaces/storage=] and [=address spaces/uniform=] address spaces
have different buffer layout constraints which are described in this section.

Note: All [=address spaces=] except [=address spaces/uniform=] have the same
constraints as the [=address spaces/storage=] address space.

All structure and array types directly or indirectly referenced by a variable
[=shader-creation error|must=] obey the constraints of the variable's address space.
Violations of an address space constraint results in a [=shader-creation error=].

In this section we define <dfn noexport>RequiredAlignOf</dfn>(|S|, |C|) as the
byte offset [=alignment=] requirement of values of host-shareable type |S| when
used in address space |C|.

<table class='data'>
  <caption>
    Alignment requirements of a host-shareable type for
    [=address spaces/storage=] and [=address spaces/uniform=] address spaces
  </caption>
  <thead>
    <tr><th>Host-shareable type |S|
        <th>[=RequiredAlignOf=](|S|, [=address spaces/storage=])
        <th>[=RequiredAlignOf=](|S|, [=address spaces/uniform=])
  </thead>
  <tr><td>[=i32=], [=u32=], [=f32=], or [=f16=]
      <td>[=AlignOf=](|S|)
      <td>[=AlignOf=](|S|)
  <tr><td>[=atomic types|atomic=]&lt;T&gt;
      <td>[=AlignOf=](|S|)
      <td>[=AlignOf=](|S|)
  <tr><td>[=vector|vec=]N&lt;T&gt;
      <td>[=AlignOf=](|S|)
      <td>[=AlignOf=](|S|)
  <tr algorithm="alignment of a matrix with C columns and R rows">
      <td>[=matrix|mat=]CxR&lt;T&gt;
      <td>[=AlignOf=](|S|)
      <td>[=AlignOf=](|S|)
  <tr algorithm="alignment of an array">
      <td>[=array=]&lt;T, N&gt;
      <td>[=AlignOf=](|S|)
      <td>[=roundUp=](16, [=AlignOf=](|S|))
  <tr algorithm="alignment of an runtime-sized array">
      <td>array&lt;T&gt;
      <td>[=AlignOf=](|S|)
      <td>[=roundUp=](16, [=AlignOf=](|S|))
  <tr algorithm="alignment of a structure">
      <td>[=structure|struct=] |S|
      <td>[=AlignOf=](|S|)
      <td>[=roundUp=](16, [=AlignOf=](|S|))<br>
</table>

Structure members of type |T| [=shader-creation error|must=] have a byte offset
from the start of the structure that is a multiple of the [=RequiredAlignOf=](|T|, |C|)
for the address space |C|:

<p algorithm="structure member minimum alignment">
    [=OffsetOfMember=](|S|, |M|) = |k| &times; [=RequiredAlignOf=](|T|, C)<br>
    Where |k| is a positive integer and |M| is a member of structure |S| with type |T|
</p>

Arrays of element type |T| [=shader-creation error|must=] have an [=element stride=] that is a
multiple of the [=RequiredAlignOf=](|T|, |C|) for the address space |C|:

<p algorithm="array element minimum alignment">
    [=StrideOf=](array<|T|, |N|>) = |k| &times; [=RequiredAlignOf=](|T|, C)<br>
    [=StrideOf=](array<|T|>) = |k| &times; [=RequiredAlignOf=](|T|, C)<br>
    Where |k| is a positive integer
</p>

Note: [=RequiredAlignOf=](|T|, |C|) does not impose any additional restrictions
on the values permitted for an [=attribute/align=] attribute, nor does it affect the rules
of [=AlignOf=](|T|). Data is laid out with the rules defined in previous
sections and then the resulting layout is validated against the
[=RequiredAlignOf=](|T|, |C|) rules.

The [=address spaces/uniform=] address space also requires that:
* Array elements are aligned to 16 byte boundaries.
    That is, [=StrideOf=](array&lt;|T|,|N|&gt;) = 16 &times; |k|' for some positive integer |k|'.
* If a structure member itself has a structure type `S`, then the number of
    bytes between the start of that member and the start of any following member
    [=shader-creation error|must=] be at least [=roundUp=](16, [=SizeOf=](S)).

Note: The following examples show how to use [=attribute/align=] and [=attribute/size=] attributes
on structure members to satisfy layout requirements for uniform buffers.
In particular, these techniques can be used mechanically transform a GLSL buffer with std140 layout
to WGSL.

<div class='example wgsl global-scope' heading='Satisfying offset requirements for uniform address space'>
  <xmp highlight=wgsl>
    struct S {
      x: f32
    }
    struct Invalid {
      a: S,
      b: f32 // invalid: offset between a and b is 4 bytes, but must be at least 16
    }
    @group(0) @binding(0) var<uniform> invalid: Invalid;

    struct Valid {
      a: S,
      @align(16) b: f32 // valid: offset between a and b is 16 bytes
    }
    @group(0) @binding(1) var<uniform> valid: Valid;
  </xmp>
</div>

<div class='example wgsl global-scope' heading='Satisfying stride requirements for uniform address space'>
  <xmp highlight=wgsl>
    struct small_stride {
      a: array<f32,8> // stride 4
    }
    // Invalid, stride must be a multiple of 16
    @group(0) @binding(0) var<uniform> invalid: small_stride;

    struct wrapped_f32 {
      @size(16) elem: f32
    }
    struct big_stride {
      a: array<wrapped_f32,8> // stride 16
    }
    @group(0) @binding(1) var<uniform> valid: big_stride;     // Valid
  </xmp>
</div>

## Memory Model ## {#memory-model}

In general, WGSL follows the [[!VulkanMemoryModel|Vulkan Memory Model]].
The remainder of this section describes how WGSL programs map to the
Vulkan Memory Model.

Note: The Vulkan Memory Model is a textual version of a [formal Alloy
model](https://github.com/KhronosGroup/Vulkan-MemoryModel/blob/master/alloy/spirv.als).

### Memory Operation ### {#memory-operation}

In WGSL, a [=read access=] is equivalent to a memory read operation in
the Vulkan Memory Model.
In WGSL, a [=write access=] is equivalent to a memory write operation in
the Vulkan Memory Model.

A [=read access=] occurs when an invocation executes one of the following:
* An evaluation of the [=Load Rule=]
* Any [[#texture-builtin-functions|texture builtin function]] except:
    * [[#texturedimensions|textureDimensions]]
    * [[#texturestore|textureStore]]
    * [[#texturenumlayers|textureNumLayers]]
    * [[#texturenumlevels|textureNumLevels]]
    * [[#texturenumsamples|textureNumSamples]]
* Any atomic built-in function except [[#atomic-store|atomicStore]]
* A [[#workgroupUniformLoad-builtin|workgroupUniformLoad]] built-in function
* A [=compound assignment=] statement (for the [=left-hand side=] expression)

A [=write access=] occurs when an invocation executes one of the following:
* An [=statement/assignment=] statement ([=simple assignment|simple=] or
    [=compound assignment|compound=] for the [=left-hand side=] expression)
* A [[#texturestore|textureStore]] built-in function
* Any atomic built-in function except [[#atomic-load|atomicLoad]]
    * [[#atomic-rmw|atomicCompareExchangeWeak]] only performs a write if the
        `exchanged` member of the returned result is `true`

[[#atomic-rmw|Atomic read-modify-write]] built-in functions perform a single
memory operation that is both a [=read access=] and a [=write access=].

Read and write accesses do not occur under any other circumstances.
Read and write accesses are collectively known as [=memory model memory
operation|memory operations=] in the Vulkan Memory Model.

A memory operation accesses exactly the set of [=memory location|locations=]
associated with the particular [=memory view=] used in the operation.  For
example, a memory read that accesses a [=u32=] from a struct containing
multiple members, only reads the memory locations associated with that u32
member.

Note: A write access to a component of a vector **may** access all memory locations
associated with that vector.

<div class='example wgsl memory locations accessed' heading="Accessing memory locations">
  <xmp highlight=wgsl>
    struct S {
      a : f32,
      b : u32,
      c : f32
    }

    @group(0) @binding(0)
    var<storage> v : S;

    fn foo() {
      let x = v.b; // Does not access memory locations for v.a or v.c.
    }
  </xmp>
</div>

### Memory Model Reference ### {#memory-model-reference}

Each module-scope [=resource=] variable forms a [=memory model reference=] for
the unique [=attribute/group=] and [=attribute/binding=] pair.
Each other variable (i.e. variables in the [=address spaces/function=],
[=address spaces/private=], and [=address spaces/workgroup=] address spaces)
forms a unique [=memory model reference=] for the lifetime of the variable.

### Scoped Operations ### {#scoped-operations}

When an invocation performs a scoped operation, it will affect one or two sets
of invocations.
These sets are the memory scope and the execution scope.  The <dfn
noexport>memory scope</dfn> specifies the set of invocations that will see any
updates to memory contents affected by the operation.
For [[#sync-builtin-functions|synchronization built-in functions]], this also
means that all affected memory operations program ordered before the function
are visible to affected operations program ordered after the function.
The <dfn noexport>execution scope</dfn> specifies the set of invocations which
may participate in an operation (see [[#collective-operations]]).

[[#atomic-builtin-functions|Atomic built-in functions]] map to [=memory model atomic
operation|atomic operations=] whose memory [=memory model scope|scope=] is:
* `Workgroup` if the atomic pointer is in the [=address spaces/workgroup=]
    address space
* `QueueFamily` if the atomic pointer is in the [=address spaces/storage=]
    address space

[[#sync-builtin-functions|Synchronization built-in functions]] map to control
barriers whose execution and memory [=memory model scope|scopes=] are
`Workgroup`.

Implicit and explicit [[#derivatives|derivatives]] have an implicit [=quad=]
execution scope.

Note: If the Vulkan memory model is not enabled in generated shaders, `Device`
scope should be used instead of `QueueFamily`.

### Memory Semantics ### {#memory-semantics}

All [[#atomic-builtin-functions|Atomic built-in functions]] use `Relaxed`
[=memory model memory semantics|memory semantics=] and, thus, no storage class
semantics.

Note: Address space in WGSL is equivalent to storage class in SPIR-V.

[[#sync-builtin-functions|workgroupBarrier]] uses `AcquireRelease` [=memory
model memory semantics|memory semantics=] and `WorkgroupMemory` semantics.
[[#sync-builtin-functions|storageBarrier]] uses `AcquireRelease` [=memory model
memory semantics|memory semantics=] and `UniformMemory` semantics.
[[#sync-builtin-functions|textureBarrier]] uses `AcquireRelease` [=memory model
memory semantics|memory semantics=] and `ImageMemory` semantics.

Note: A combined `workgroupBarrier` and `storageBarrier` uses `AcquireRelease`
ordering semantics and both `WorkgroupMemory` and `UniformMemory` memory
semantics.

Note: No atomic or synchronization built-in functions use `MakeAvailable` or
`MakeVisible` semantics.

### Private vs Non-private ### {#private-vs-non-private}

All non-atomic [=read accesses=] in the [=address spaces/storage=] or
[=address spaces/workgroup=] address spaces are considered
[=memory model non-private|non-private=] and correspond to read operations with
`NonPrivatePointer | MakePointerVisible` memory operands with the `Workgroup`
scope.

All non-atomic [=write accesses=] in the [=address spaces/storage=] or
[=address spaces/workgroup=] address spaces are considered
[=memory model non-private|non-private=] and correspond to write operations
with `NonPrivatePointer | MakePointerAvailable` memory operands with the
`Workgroup` scope.

# Execution # {#execution}

[[#overview]] describes how a shader is invoked and partitioned into [=invocations=].
This section describes further constraints on how invocations execute,
individually and collectively.

## Program Order Within an Invocation ## {#program-order}

Each statement in a WGSL module may be executed zero or more times during
execution.
For a given invocation, each execution of a given statement represents a unique
<dfn noexport>dynamic statement instance</dfn>.

When a statement includes an expression, the statement’s semantics determines:
* Whether the expression is evaluated as part of statement execution.
* The relative ordering of evaluation between independent expressions in the statement.

Expression nesting defines data dependencies which must be satisfied to
complete evaluation.
That is, a nested expression must be evaluated before the enclosing expression
can be evaluated.
The order of evaluation for operands of an expression is left-to-right in
WGSL.
For example, `foo() + bar()` must evaluate `foo()` before `bar()`.
See [[#expressions]].

Statements in a WGSL module are executed in control flow order.
See [[#statements]] and [[#function-calls]].

## Uniformity ## {#uniformity}

A [[#collective-operations|collective operation]]
(e.g. barrier, derivative, or a texture operation relying on an implicitly computed derivative)
requires coordination among different invocations running concurrently on the GPU.
The operation executes correctly and portably
when all invocations execute it concurrently, i.e. in [=uniform control flow=].

Conversely, incorrect or non-portable behavior occurs when a strict subset of invocations
execute the operation, i.e. in non-uniform control flow.
Informally, some invocations reach the collective operation, but others do not,
or not at the same time, as a result of non-uniform control dependencies.
Non-uniform control dependencies arise from [[#control-flow|control flow]]
statements whose behavior depends on [=uniform value|non-uniform values=].

> For example, a non-uniform control dependency arises when different invocations compute
    different values for the condition of an
    [=statement/if=], [=statement/break-if=], [=statement/while=], or [=statement/for=],
    different values for the selector of a [=statement/switch=],
    or the left-hand operand of a short-circuiting binary operator (`&&` or `||`).

These non-uniform values can often be traced back to certain sources that are not
statically proven to be uniform.
These sources include, but are not limited to:
* Mutable [=module scope|module-scope=] [=variables=]
* Most [=built-in values=], except [=built-in values/num_workgroups=] and [=built-in values/workgroup_id=]
* [=user-defined input datum|User-defined inputs=]
* Certain [=built-in functions=] (see [[#uniformity-function-calls]])

To ensure correct and portable behavior, a WGSL implementation [=behavioral requirement|will=]
perform a static <dfn>uniformity analysis</dfn>, attempting to prove that each collective operation
executes in [=uniform control flow=].
Subsequent subsections describe the analysis.

A <dfn noexport>uniformity failure</dfn> [=behavioral requirement|will=] be triggered
when [=uniformity analysis=] cannot prove that a particular [[#collective-operations|collective operation]] executes in [=uniform control flow=].
* If a uniformity failure is triggered for a
    [=builtin functions that compute a derivative|builtin function that computes a derivative=], then
    a [=trigger/derivative_uniformity=] [=diagnostic=] is [=triggered=].
    * The diagnostic's [=diagnostic/triggering location=] is the location of the [=call site=] of that builtin.
    * The diagnostic's [=diagnostic/severity=] defaults to an [=severity/error=] but can be controlled with a [=diagnostic filter=].
* If a uniformity failure is triggered for a [[#sync-builtin-functions|synchronization builtin]],
    an [=severity/error=] [=diagnostic=] is [=triggered=],
    which results in a [=shader-creation error=].

### Terminology and Concepts ### {#uniformity-concepts}

The following definitions are merely informative, trying to give an intuition for what the analysis in the next subsection is computing.
The analysis is what actually defines these concepts, and when a program is valid or breaks the uniformity rules.

For a given group of invocations:
- If all invocations in a given scope execute as if they are executing in lockstep at a given
    point in the program, that point is said to have <dfn noexport>uniform control flow</dfn>.
    - For a [=compute shader stage=], the scope of uniform control flow is all invocations
        in the same [=compute shader stage/workgroup=].
    - For other shader stages, the scope of uniform control flow is all invocations for that
        [=entry point=] in the same [=draw command=].
- If an expression is executed in uniform control flow, and all invocations compute the
    same value, it is said to be a <dfn noexport>uniform value</dfn>.
- If invocations hold the same value for a local variable at every point where it is live,
    it is said to be a <dfn noexport>uniform variable</dfn>.

### Uniformity Analysis Overview ### {#uniformity-overview}

The remaining subsections specify a static analysis that verifies that
[[#collective-operations|collective operations]] are only executed in [=uniform
control flow=].

The analysis assumes [=dynamic errors=] do not occur.
A shader stage with a [=dynamic error=] is already non-portable, no matter the outcome
of uniformity analysis.

<div class="note"><span class=marker>Note:</span>This analysis has the following desirable properties:
      - Sound, meaning that a [=uniformity failure=] [=behavioral requirement|will=] be triggered for a program that would break the uniformity requirements of builtins.
      - Refactoring a piece of code into a function, or inlining a function, cannot make a shader invalid if it was valid before the transformation.
      - If the analysis refuses a program, it provides a straightforward chain of implications that can be used by the user agent to craft a good error message.
</div>

Each function is analyzed, trying to ensure two things:
    * Uniformity requirements are satisfied when it calls other functions, and
    * Uniformity requirements are satisfied whenever it is called.
A [=uniformity failure=] is triggered if either of these two checks fail.

As part of this work, the analysis computes metadata about the function to help analyze its callers in turn.
This means that the call graph must first be built, and functions must be analyzed from the leaves upwards, i.e. from functions that call no function outside the standard library toward the entry point.
This way, whenever a function is analyzed, the metadata for all of its callees has already been computed.
There is no risk of being trapped in a cycle, as recurrence is forbidden in the language.

Note: Another way of saying the same thing is that we do a topological sort of functions ordered by the "is a (possibly indirect) callee of" partial order, and analyze them in that order.

Additionally, for each function call, the analysis computes and propagates
the set of [=diagnostic/triggering rules=], if any, that would be triggered if that call cannot be proven to be in uniform control flow.
We call this the <dfn noexport>potential-trigger-set</dfn> for the call.
The elements of this set are drawn from two possibilites:
* [=trigger/derivative_uniformity=], for functions relying on computing a derivative, or
* an unnamed triggering rule, for the uniformity requirements that cannot be filtered.
    * This is used for compute shader functions relying on [[#sync-builtin-functions|synchronization functions]].

### Analyzing the Uniformity Requirements of a Function ### {#uniformity-function}

Each function is analyzed in two phases.

The first phase walks over the syntax of the function, building a directed graph along the way based on the rules in the following subsections.
The second phase explores that graph, computing the constraints on calling this function,
and potentially triggering a [=uniformity failure=].

<div class="note"><span class=marker>Note:</span>Apart from four special nodes
    [=RequiredToBeUniform.error=],
    [=RequiredToBeUniform.warning=],
    [=RequiredToBeUniform.info=], and [=MayBeNonUniform=], each node can be understood as capturing the truth-value one of the following statements:
        - A specific point of the program must be executed in [=uniform control flow=].
        - An expression must be a [=uniform value=].
        - A variable must be a [=uniform variable=].
        - A value stored in memory, that could be loaded via a pointer, must be a [=uniform value=].

        An edge can be understood as an implication from the statement corresponding to its source node to the statement corresponding to its target node.

        For example, one uniformity requirement is that the `workgroupBarrier` builtin function must only be called within uniform control flow.
        To express this, we add an edge from [=RequiredToBeUniform.error=] to the node corresponding to the `workgroupBarrier` [=call site=].
        One way to understand this is that [=RequiredToBeUniform.error=] corresponds to the proposition True,
        so that [=RequiredToBeUniform.error=] -> X is the same as saying that X is true.

        Reciprocally, to express that we cannot ensure the uniformity of something (e.g. a variable which holds the thread id), we add an edge from the corresponding node to [=MayBeNonUniform=].
        One way to understand this, is that [=MayBeNonUniform=] corresponds to the proposition False, so that X -> [=MayBeNonUniform=] is the same as saying that X is false.

        A consequence of this interpretation is that every node reachable from [=RequiredToBeUniform.error=] corresponds to
        something which is required to be uniform for the program to be valid, and every node from which
        [=MayBeNonUniform=] is reachable corresponds to something whose uniformity we cannot guarantee.
        It follows that we have a uniformity violation, triggering a [=uniformity failure=], if there is any
        path from [=RequiredToBeUniform.error=] to [=MayBeNonUniform=].

        The nodes [=RequiredToBeUniform.warning=] and [=RequiredToBeUniform.info=] are used in a similar way,
        but instead help determine when [=severity/warning=] or [=severity/info=] [=diagnostics=] should be triggered:
        *   If there is a path from [=RequiredToBeUniform.warning=] to [=MayBeNonUniform=], then a [=severity/warning=]
            [=diagnostic=] will be triggered.
        *   If there is a path from [=RequiredToBeUniform.info=] to [=MayBeNonUniform=], then an [=severity/info=]
            [=diagnostic=] will be triggered.

        As described in [[#diagnostics]], lower severity diagnostics may be discarded if higher severity diagnostics have also been generated.
</div>

For each function, two tags are computed:
  * A <dfn noexport>call site tag</dfn> describing the control flow uniformity requirements on the [=call sites=] of the function, and
  * A <dfn noexport>function tag</dfn> describing the function's effects on uniformity.

For each [=formal parameter=] of a function, one or two tags are computed:
  * A <dfn noexport>parameter tag</dfn> describes the uniformity requirement of the parameter value.
  * A <dfn noexport>parameter return tag</dfn> describes how the uniformity of the parameter influences that of the function's [=return value=].
  * A <dfn noexport>pointer parameter tag</dfn>, when the parameter type is a pointer into the  [=address spaces/function=] address space.
      The tag describes whether the value in the memory pointed to by the parameter may become
      [=uniform value|non-uniform=] during the execution of the function call.

<table class='data'>
  <caption>[=Call site tag=] values</caption>
  <thead>
    <tr><th>Call Site Tag<th>Description
  </thead>
  <tr algorithm="CallSiteRequiredToBeUniform tag">
      <td><dfn noexport>CallSiteRequiredToBeUniform.S</dfn>,<br>
          where |S| is one of the severities: [=severity/error=], [=severity/warning=], or [=severity/info=].
      <td>The function must only be called from [=uniform control flow=].
          Otherwise a diagnostic with severity |S| will be triggered.

          Associated with a [=potential-trigger-set=].
  <tr><td><dfn noexport>CallSiteNoRestriction</dfn>
      <td>The function may be called from [=uniform control flow|non-uniform control flow=].
</table>

<table class='data'>
  <caption>[=Function tag=] values</caption>
  <thead>
    <tr><th>Function Tag<th>Description
  </thead>
  <tr><td><dfn noexport>ReturnValueMayBeNonUniform</dfn>
      <td>The [=return value=] of the function may be non-uniform.
  <tr><td><dfn noexport>NoRestriction</dfn>
      <td>The function does not introduce non-uniformity.
</table>

<table class='data'>
  <caption>[=Parameter tag=] values</caption>
  <thead>
    <tr><th>Parameter Tag<th>Description
  </thead>
  <tr algorithm="ParameterRequiredToBeUniformValue tag">
      <td><dfn noexport>ParameterRequiredToBeUniform.S</dfn>,<br>
          where |S| is one of the severities: [=severity/error=], [=severity/warning=], or [=severity/info=].
      <td>The parameter must be a [=uniform value=].
          If the parameter type is a pointer, the memory view, but not
          necessarily its contents, must be uniform.
          Otherwise a diagnostic with severity |S| will be triggered.

          Associated with a [=potential-trigger-set=].
  <tr algorithm="ParameterContentsRequiredToBeUniform tag">
      <td><dfn noexport>ParameterContentsRequiredToBeUniform.S</dfn>,<br>
          where |S| is one of the severities: [=severity/error=], [=severity/warning=], or [=severity/info=].
      <td>The value stored in the memory pointed to by the pointer parameter must be a [=uniform value=].
          Otherwise a diagnostic with severity |S| will be triggered.

          Associated with a [=potential-trigger-set=].
  <tr><td><dfn noexport>ParameterNoRestriction</dfn>
      <td>The parameter value has no uniformity requirement.
</table>

<table class='data'>
  <caption>[=Parameter return tag=] values</caption>
  <thead>
    <tr><th>Parameter Return Tag<th>Description
  </thead>
  <tr><td><dfn noexport>ParameterReturnContentsRequiredToBeUniform</dfn>
      <td>The parameter [=shader-creation error|must=] be a [=uniform value=] in order for the [=return value=] to be a uniform value.
      If the parameter is a pointer, then the values stored in the memory pointed to by the pointer must also be [=uniform value|uniform=].
  <tr><td><dfn noexport>ParameterReturnNoRestriction</dfn>
      <td>The parameter value has no uniformity requirement.
</table>

<table class='data'>
  <caption>[=Pointer parameter tag=] values</caption>
  <thead>
    <tr><th>Pointer Parameter Tag<th>Description
  </thead>
  <tr><td><dfn noexport>PointerParameterMayBeNonUniform</dfn>
      <td>The value stored in the memory pointed to by the pointer parameter may be [=uniform value|non-uniform=] after the function call.
  <tr><td><dfn noexport>PointerParameterNoRestriction</dfn>
      <td>The uniformity of the value stored in the memory pointed to by the pointer parameter is unaffected by the function call.
</table>

The following algorithm describes how to compute these tags for a given function:

* Create the following nodes:
    * <dfn noexport>RequiredToBeUniform.error</dfn>, <dfn noexport>RequiredToBeUniform.warning</dfn>, and <dfn noexport>RequiredToBeUniform.info</dfn>.
        Collectively these are called the <dfn noexport>RequiredToBeUniform.S</dfn> nodes.
        * Each such node is associated with a [=potential-trigger-set=], which is initially empty.
    * <dfn noexport>MayBeNonUniform</dfn>
    * <dfn noexport>CF_start</dfn>, representing the uniformity requirement for control flow when the function begins executing.
    * <dfn noexport>param_i</dfn>, where *i* ranges over the function's [=formal parameters=].
    * If the function has a [=return type=], create a node called <dfn noexport>Value_return</dfn>.
* Desugar pointers as described in [[#pointer-desugar]].
    * For each formal parameter that is a pointer in the [=address spaces/function=] address space,
        create the following nodes:
        * <dfn noexport>param_i_contents</dfn>: this represents the uniformity of the contents of the memory view.
        * <dfn noexport>Value_return_i_contents</dfn>: this represents the function's effects on the uniformity of the contents of the memory view.
* Walk over the syntax of the function, adding nodes and edges to the graph following the rules of the next sections ([[#func-var-value-analysis]], [[#uniformity-statements]], [[#uniformity-function-calls]], [[#uniformity-expressions]]), using [=CF_start=] as the starting control-flow for the function's body.
    * The nodes added in this step are called <dfn noexport>interior nodes</dfn>.
* Initialize as follows:
    * The [=function tag=] is initialized to [=NoRestriction=].
    * The [=call site tag=] is initialized to [=CallSiteNoRestriction=].
    * The [=parameter tag=] for each [=param_i=] is initialized to [=ParameterNoRestriction=].
    * The [=parameter return tag=] for each [=param_i=] is initialized to [=ParameterReturnNoRestriction=].
    * The [=pointer parameter tag=] for each [=param_i=], if it exists, is initialized to [=PointerParameterNoRestriction=].
* For each severity *S* in the order {[=severity/error=], [=severity/warning=], [=severity/info=]}, perform the following:
    * Let *R.S* be the set of unvisited nodes reachable from [=RequiredToBeUniform.S=].
    * Mark the [=interior nodes=] in *R.S* as visited.
    * Let *PTS* be the [=potential-trigger-set=] associated with [=RequiredToBeUniform.S=].
    * If *R.S* includes the node [=MayBeNonUniform=], then trigger a [=uniformity failure=]:
         * [=triggered|Trigger=] a diagnostic with severity *S* and triggering rule *t*, for each *t* in *PTS*.
    * Otherwise:
        * If *R.S* includes [=CF_start=], and the [=call site tag=] has not been updated since initialization, then
             set the [=call site tag=] to [=CallSiteRequiredToBeUniform.S=], and set its [=potential-trigger-set=] to *PTS*.
        * For each [=param_i=] in *R.S*, if its corresponding [=parameter tag=] has not been updated since initialization, then
             set that tag to [=ParameterRequiredToBeUniform.S=], and set its [=potential-trigger-set=] to *PTS*.
        * For each [=param_i_contents=] in *R.S*, if its corresponding [=parameter tag=] has not been updated since initialization, then
             set that tag to [=ParameterContentsRequiredToBeUniform.S=], and set its [=potential-trigger-set=] to *PTS*.
* Mark all the [=interior nodes=] as unvisited.
* If [=Value_return=] exists, let *VR* be the set of nodes reachable from [=Value_return=].
    * If *VR* includes [=MayBeNonUniform=], then set the [=function tag=] to [=ReturnValueMayBeNonUniform=].
    * For each [=param_i=] in *VR*, set the corresponding [=parameter return tag=] to [=ParameterReturnContentsRequiredToBeUniform=].
* For each [=Value_return_i_contents=] node, let *VRi* be the set of nodes reachable from [=Value_return_i_contents=].
    * If *VRi* includes [=MayBeNonUniform=], set the corresponding [=pointer parameter tag=] to [=PointerParameterMayBeNonUniform=].

Note: The entire graph can be destroyed at this point. The tags described above are all that we need to remember to analyze callers of this function.
However, the graph contains information that can be used to provide more informative diagnostics.
For example a value in a one function may not be provably [=uniform value|uniform=],
which then contributes to triggering a uniformity failure in another function.
An informative diagnostic would describe the non-uniform value, as well as the function call at the diagnostic's
[=diagnostic/triggering location|triggered location=].

### Pointer Desugaring ### {#pointer-desugar}

Each [=formal parameter|parameter=] of [=pointer type=] in the [=address
spaces/function=] address space is desugared as a local variable declaration
whose initial value is equivalent to dereferencing the parameter.
That is, function address space pointers are viewed as aliases to a local
variable declaration.
The initial value assignment produces an edge to [=param_i_contents=] for
*i*<sup>th</sup> parameter (i.e. *V(e)* is [=param_i_contents=]).

Each [=let-declaration=], *L*, with an [=effective-value-type=] that is a [=pointer type=] is desugared as follows:
* Visit each subexpression, *SE*, of the initializer expression of *L* in a postorder depth-first traversal:
    * If  *SE* invokes the [=load rule=] during [=type checking=] and the [=root identifier=]
        is a mutable variable then:
        * Create a new let-declaration, *LSE*, immediately prior to *L* initialized with *SE*.
        * Replace *SE* in *L* with a [[#value-identifier-expr|value identifier expression]]
            composed of *LSE*.
* Record the, possibly updated, initializer expression of *L*.
* Substitute each [=identifier=] that [=resolves=] to *L* with the recorded
    initializer expression (wrapped in a [[#parenthesized-expressions|parenthesized expression]]).

This desugaring simplifies the subsequent analyses by exposing the [=root identifier=]
of the pointer directly at each of its uses.

Note: For the purposes of uniformity analysis [=type checking=] is described to
occur both before and after this desugaring has occurred.

<div class='example wgsl' heading='pointers in the uniformity analysis'>
  <xmp highlight=wgsl>
    fn foo(p : ptr<function, array<f32, 4>>, i : i32) -> f32 {
      let p1 = p;
      var x = i;
      let p2 = &((*p1)[x]);
      x = 0;
      *p2 = 5;
      return (*p1)[x];
    }

    // This is the equivalent version of foo for the analysis.
    fn foo_for_analysis(p : ptr<function, array<f32, 4>>, i : i32) -> f32 {
      var p_var = *p;            // Introduce variable for p.
      let p1 = &p_var;           // Use the variable for p1
      var x = i;
      let x_tmp1 = x;            // Capture value of x
      let p2 = &(p_var[x_tmp1]); // Substitute p1's initializer
      x = 0;
      *(&(p_var[x_tmp1])) = 5;   // Substitute p2's initializer
      return (*(&p_var))[x];     // Substitute p1's initializer
    }
  </xmp>
</div>

### Function-scope Variable Value Analysis ### {#func-var-value-analysis}

The value of each [=function scope|function-scope=] [=variable=] at a
particular statement can be analyzed in terms of the assignments that reach it
and, potentially, its initial value.

An assignment is a <dfn noexport>full assignment</dfn> if:
* The variable's [=effective-value-type=] is a [=scalar=] type, or
* the variable's [=effective-value-type=] is a [=composite=] type and each
    [=component=] of the composite is assigned a value.

Otherwise, an assignment is a <dfn noexport>partial assignment</dfn>.

A <dfn>full reference</dfn> is an expression of [=reference type=] that is one of:
* an identifier *x* that [=resolves=] to a variable, or
* `(`*r*`)` where *r* is a [=full reference=], or
* `*`*p* where *p* is a [=full pointer=].

A <dfn>full pointer</dfn> is an expression of [=pointer type=] that is one of:
* `&`*r* where *r* is a [=full reference=], or
* an identifier *p* that [=resolves=] to a [=let-declaration=] initialized to a [=full pointer=], or
* `(`*p*`)` where *p* is a [=full pointer=].

Note: For the purposes of this analysis, we don't need the case where
a formal parameter of pointer type may be a full pointer.

A [=full reference=], and similarly a [=full pointer=], is a [=memory view=]
for *all* the memory locations for the corresponding [=originating variable=] *x*.

A reference that is not a [=full reference=] is a <dfn noexport>partial reference</dfn>.
As such, a partial reference is either:
* a memory view for a strict subset of the memory locations
    for the corresponding [=originating variable=], or
* a memory view the with same set of locations as the corresponding
    originating variable, but with a different [=store type=].

<div class="note">
<span class=marker>Note:</span> A [=partial reference=] can still cover all the same memory locations
as a full reference, i.e. all the locations used by a variable declaration.
This can occur when the store type is a structure type having only one member,
or when the store type is an array type with one element.

Consider a structure type with a single member, and a variable storing that type:

```wgsl
     struct S { member: i32; }
     fn foo () {
        var v: S;
     }
```

Then `v` is a full reference and `v.member` is a partial reference.
Their memory views cover the same memory
locations, but the store type for `v` is `S` and the store type of `v.s` is `i32`.

A similar situation occurs with arrays having a single element:

```wgsl
     fn foo () {
        var arr: array<i32,1>;
     }
```

Then `arr` is a full reference and `arr[0]` is a partial reference.
Their memory views cover the same memory
locations, but the store type for `arr` is `array<i32,1>` and the store type of `arr[0]` is `i32`.

To simplify analysis, an assignment via *any* kind of [=partial reference=] is treated as if
it does *not* modify every memory location in the associated [=originating variable=].
This causes the analysis to be conservative, potentially triggering a [=uniformity failure=] for
more programs than strictly necessary.
</div>

An assignment through a [=full reference=] is a [=full assignment=].

An assignment through a [=partial reference=] is a [=partial assignment=].

When the uniformity rules in subsequent sections refer to the value for a
function-scope variable used as an [=RHSValue=], it means the value of the variable
prior to evaluation of the RHSValue expression.
When the uniformity rules in subsequent sections refer to the value for a
function-scope variable used as an [=LHSValue=], it means the value of the variable
after execution of the statement the expression appears in.

Multiple assignments to a variable might reach a use of that variable due to
[[#control-flow|control-flow statements]] or partial assignments.
The analysis joins multiple assignments reaching out of control-flow statements
by unioning the set of assignments that reach each control-flow exit.

The following table describes the rules for joining assignments.
In the uniformity graph, each join is an edge from the result node to node
representing the source of the value.
It is written in terms of an arbitrary variable `x`. It uses the following
notations:
* *Vin*(*S*) is the value of `x` prior the execution of the statement *S*.
* *Vout*(*S*) is the value of `x` after the execution of the statement *S*.
* *Vout*(*prev*) is the value of `x` prior to the execution of the current statement.
* *Vin*(*next*) is the value of `x` prior to the execution of the next statement.
* *V*(*e*) is a value node for an expression as in the subsequent sections.
* *V*(*0*) is the zero value of `x`'s [=effective-value-type=].

<table class='data'>
  <caption>Rules for joining multiple assignments to a function-scope variable.
  <thead>
    <tr><th>Statement
        <th>Result
        <th>Edges from the Result
  </thead>
  <tr><td>
          var *x*;
      <td>*Vin*(*next*)
      <td>*V*(*0*)
  <tr><td>
          var *x* = *e*;<br>
      <td rowspan=3>*Vin*(*next*)
      <td rowspan=3>*V*(*e*)

          Note: This is a [=full assignment=] to *x*.
  <tr><td>
          *x* = *e*;<br>
  <tr><td>
          *r* = *e*;<br>
          where *r* is a [=full reference=] to variable *x*
  <tr><td>
          *r* = *e*;<br>
          where *r* is a [=partial reference=] to variable *x*
      <td>*Vout*(*S*)
      <td>*V*(*e*), *V*(*prev*)

          Note: This is a [=partial assignment=] to *x*.

          Note: Partial assignments include the previous value.
          The assignment either writes only a subset of the stored components,
          or the type of the written value differs from the [=store type=]
          of the [=originating=] variable.
  <tr><td>*s1* *s2*<br>
          where *Next* is in behavior of *s1*.

          Note: *s1* often ends in a semicolon.
      <td>*Vin*(*s2*)
      <td>*Vout*(*s1*)
  <tr><td>
          if *e* *s1* else *s2*<br>
          where *Next* is in the behaviors of both *s1* and *s2*
      <td>*Vin*(*next*)
      <td>*Vout*(*s1*), *Vout*(*s2*)
  <tr><td>
          if *e* *s1* else *s2*<br>
          where *Next* is in the behavior of *s1*, but not *s2*
      <td>*Vin*(*next*)
      <td>*Vout*(*s1*)
  <tr><td>
          if *e* *s1* else *s2*<br>
          where *Next* is in the behavior of *s2*, but not *s1*
      <td>*Vin*(*next*)
      <td>*Vout*(*s2*)
  <tr><td>loop { *s1* continuing { *s2* } }
      <td>*Vin*(*s1*)
      <td>*Vout*(*prev*), *Vout*(*s2*)
  <tr><td>loop { *s1* continuing { *s2* } }
      <td>*Vin*(*s2*)
      <td>*Vout*(*s1*),<br>
          *Vout*(*s*<sub>i</sub>)<br>
          for all *s*<sub>i</sub> in *s1* whose behavior is {*Continue*} and transfer control to *s2*
  <tr><td>loop { *s1* continuing { *s2* } }
      <td>*Vin*(*next*)
      <td>*Vout*(*s2*),<br>
          *Vout*(*s*<sub>i</sub>)<br>
          for all *s*<sub>i</sub> in *s1* whose behavior is {*Break*} and transfer control to *next*
  <tr><td>switch *e* {<br>
            case _: *s1*<br>
            case _: *s2*<br>
            ...<br>
            case _: *s3*<br>
          }<br>
      <td>*Vin*(*s*<sub>i</sub>)
      <td>*Vout*(*prev*)
  <tr><td>switch *e* {<br>
            case _: *s1*<br>
            case _: *s2*<br>
            ...<br>
            case _: *s3*<br>
          }<br>
      <td>*Vin*(*next*)
      <td>*Vout*(*s*<sub>i</sub>),<br>
          for all *s*<sub>i</sub> whose behavior includes *Next* or *Break*, and<br>
          *Vout*(*s*<sub>j</sub>)<br>
          for all statements inside *s*<sub>j</sub> whose behavior is {*Break*} and trasfer control to *next*
</table>

For all other statements (except function calls), *Vin*(*next*) is equivalent
to *Vout*(*prev*).

Note: The same desugarings apply as in [[#behaviors|statement behavior analysis]].

### Uniformity Rules for Statements ### {#uniformity-statements}

The rules for analyzing statements take as argument both the statement itself and the node corresponding to control flow at the beginning of it (which we'll note "CF" below) and return both of the following:

* A node corresponding to control flow at the exit of it
* A set of new nodes and edges to add to the graph

In the table below, `(CF1, S) => CF2` means "run the analysis on S starting
with control flow CF1, apply the required changes to the graph, and name the
resulting control flow CF2".
Similarly, `(CF1, E) => (CF2, V)` means "run the analysis on expression E,
starting with control flow CF1, apply the required changes to the graph, and
name the resulting control flow node CF2 and the resulting value node V" (see
next section for the analysis of expressions).
This evaluation of expressions is used for any expression that is not part of
the [=left-hand side=] of an [=statement/assignment=] and is called an <dfn
noexport>RHSValue</dfn>.

There is a similar set of rules for expressions that are part of the
[=left-hand side=] of an [=statement/assignment=], the <dfn noexport>LHSValue</dfn>,
that we denote by `LHSValue: (CF, E) => (CF, L)`. Instead of computing the node
which corresponds to the uniformity of the value, it computes the node which
corresponds to the uniformity of the variable we are addressing.

Note: [=LHSValues=] include expressions in [=increment statement|increment=] and
[=decrement statement|decrement=] statements.

Note: [=RHSValues=] include expression that are part of the [=right-hand side=] of
an [=statement/assignment=] statement or expressions that are not part of an
assignment, [=increment statement|increment=], or [=decrement statement|decrement=] statement.

When several edges have to be created we use `X -> {Y, Z}` as a short-hand for `X -> Y, X -> Z`.

<table class='data'>
  <caption>Uniformity rules for statements</caption>
  <thead>
    <tr><th>Statement<th>New nodes<th>Recursive analyses<th>Resulting control flow node<th>New edges
  </thead>
  <tr><td class="nowrap">{*s*}
      <td>
      <td class="nowrap">(*CF*, *s*) => *CF'*
      <td>*CF'*
      <td>
  <tr><td class="nowrap">*s1* *s2*,<br>
        with Next in behavior of *s1*

        Note: *s1* often ends in a semicolon.

      <td>
      <td class="nowrap">(*CF*, *s1*) => *CF1*<br>
          (*CF1*, *s2*) => *CF2*
      <td>*CF2*
      <td>
  <tr><td class="nowrap">*s1* *s2*,<br>
        without Next in behavior of *s1*

        Note: *s1* often ends in a semicolon.

      <td>
      <td>(*CF*, *s1*) => *CF1*<br>

      Note: *s2* is statically unreachable and not recursively analyzed.
      *s2* does not contribute to the uniformity analysis.
      <td>*CF1*
      <td>
  <tr><td class="nowrap">if *e* *s1* else *s2*<br> with behavior {Next}
      <td>
      <td rowspan=2 class="nowrap">(*CF*, *e*) => (*CF'*, *V*)<br>
          (*V*, *s1*) => *CF1*<br>
          (*V*, *s2*) => *CF2*
      <td>*CF*
      <td>
  <tr><td class="nowrap">if *e* *s1* else *s2*<br> with another behavior
      <td>*CFend*
      <td>*CFend*
      <td class="nowrap">*CFend* -> {*CF1*, *CF2*}
  <tr><td class="nowrap">loop {*s1* continuing {*s2*}}<br> with behavior {Next}
      <td rowspan=2>*CF'*
      <td rowspan=2 class="nowrap">(*CF'*, *s1*) => *CF1*<br>
          (*CF1*, *s2*) => *CF2*
      <td>*CF*
      <td rowspan=2 class="nowrap">*CF'* -> {*CF2*, *CF*}
  <tr><td class="nowrap">loop {*s1* continuing {*s2*}}<br> with another behavior
      <td>*CF'*
  <tr><td class="nowrap">loop {*s1*}<br> with behavior {Next}
      <td rowspan=2>*CF'*
      <td rowspan=2 class="nowrap">(*CF'*, *s1*) => *CF1*
      <td>*CF*
      <td rowspan=2 class="nowrap">*CF'* -> {*CF1*, *CF*}
  <tr><td class="nowrap">loop {*s1*}<br> with another behavior
      <td>*CF'*
  <tr><td class="nowrap">switch *e* case _: *s_1* .. case _: *s_n*<br> with behavior {Next}
      <td>
      <td rowspan=2 class="nowrap">(*CF*, *e*) => (*CF'*, *V*)<br>
        (*V*, *s_1*) => *CF_1*<br>
        ...<br>
        (*V*, *s_n*) => *CF_n*
      <td>*CF*
      <td>
  <tr><td class="nowrap">switch *e* case _: *s_1* .. case _: *s_n*<br> with another behavior
      <td>*CFend*
      <td>*CFend*
      <td class="nowrap">*CFend* -> {*CF_1*, ..., *CF_n*}
  <tr><td class="nowrap">var x: T;
      <td rowspan=3>
      <td rowspan=3>
      <td rowspan=3>*CF*
      <td rowspan=3>
      Note: If x is a [=address spaces/function=] address space variable, *CF*
      is used as the zero value initializer in the
      [[#func-var-value-analysis|value analysis]].
  <tr><td class="nowrap">break;
  <tr><td class="nowrap">continue;
  <tr><td class="nowrap">break if *e*;
      <td>
      <td class="nowrap">(*CF*, *e*) => (*CF'*, *V*)
      <td>*CF'*
      <td>
  <tr><td class="nowrap">return;
      <td>
      <td>
      <td>*CF*
      <td>
      For each [=address spaces/function=] address space pointer parameter *i*,
      [=Value_return_i_contents=] -> *Vin*(*prev*) (see [[#func-var-value-analysis]])
  <tr><td class="nowrap">return *e*;
      <td>
      <td class="nowrap">(*CF*, *e*) => (*CF'*, *V*)
      <td>*CF'*
      <td>[=Value_return=] -> *V*

      For each [=address spaces/function=] address space pointer parameter *i*,
      [=Value_return_i_contents=] -> *Vin*(*prev*) (see [[#func-var-value-analysis]])
  <tr><td class="nowrap">*e1* = *e2*;
      <td>
      <td class="nowrap">[=LHSValue=]: (*CF*, *e1*) => (*CF1*, *LV*)<br>
          (*CF1*, *e2*) => (*CF2*, *RV*)
      <td>*CF2*
      <td>*LV* -> *RV*

      Note: *LV* is the result value from the [[#func-var-value-analysis|value analysis]].
  <tr><td class="nowrap">_ = *e*
      <td>
      <td class="nowrap">(*CF*, *e*) => (*CF'*, *V*)
      <td>*CF'*
      <td>
  <tr><td class="nowrap">let x = *e*;
      <td>
      <td>(*CF*, *e*) => (*CF'*, *V*)
      <td>*CF'*
      <td>
  <tr><td class="nowrap">var x = *e*;
      <td>
      <td>(*CF*, *e*) => (*CF'*, *V*)
      <td>*CF'*
      <td>Note: If x is a [=address spaces/function=] address space variable,
      *V* is used as the result value in the [[#func-var-value-analysis|value analysis]].
</table>

Analysis of [[#for-statement|for]] and [[#while-statement|while]] loops follows
from their respective desugaring translations to [[#loop-statement|loop]] statements.

In [[#switch-statement|switch]], a [=default-alone clause=] block is treated exactly like a [=case clause=] with regards to uniformity.

To maximize performance, implementations often try to minimize the amount of
[=uniform control flow|non-uniform control flow=].
However, the points at which invocations can be said to be uniform varies
depending on a number of factors.  WGSL's static analysis conservatively
assumes a return to uniform control flow occuring at the end of
[=statement/if=], [=statement/switch=], and [=statement/loop=] statements if
the [[#behaviors|behavior]] for the statement is {Next}.
This is modeled in the preceding table as the resulting control flow node
being the same as input control flow node.

### Uniformity Rules for Function Calls ### {#uniformity-function-calls}

The most complex rule is for function calls:
- For each argument, apply the corresponding expression rule, with the control flow at the exit of the previous argument (using the control flow at the beginning of the function call for the first argument). Name the corresponding value nodes <dfn noexport>arg_i</dfn> and the corresponding control flow nodes <dfn noexport>CF_i</dfn>
- Create two new nodes, named <dfn noexport>Result</dfn> and <dfn noexport>CF_after</dfn>
- If the [=call site tag=] of the function is [=CallSiteRequiredToBeUniform.S=], then:
    - Add an edge from [=RequiredToBeUniform.S=] to the last [=CF_i=].
    - Add the members of the [=potential-trigger-set=] of the [=call site tag=] to the potential-trigger-set associated with [=RequiredToBeUniform.S=].
- Add an edge from [=CF_after=] to the last [=CF_i=]
- If the [=function tag=] is [=ReturnValueMayBeNonUniform=], then add an edge from [=Result=] to [=MayBeNonUniform=]
- Add an edge from [=Result=] to [=CF_after=]
- For each argument *i*:
    - If the corresponding [=parameter tag=] is [=ParameterRequiredToBeUniform.S=], then:
        - Add an edge from [=RequiredToBeUniform.S=] to [=arg_i=].
        - Add the members of the [=potential-trigger-set=] of the [=parameter tag=] to the potential-trigger-set associated with [=RequiredToBeUniform.S=].
    - If the [=parameter return tag=] is [=ParameterReturnContentsRequiredToBeUniform=], then add an edge from [=Result=] to [=arg_i=]
    - If the corresponding parameter has a [=pointer parameter tag=] of [=PointerParameterMayBeNonUniform=], then add an edge from *Vout*(*call*) to [=MayBeNonUniform=]
    - If the parameter is a pointer in the [=address spaces/function=] address space, add an edge from *Vout*(*call*) to each corresponding [=arg_i=] for the reachable parameters recorded previously
        - If the [=parameter tag=] is [=ParameterContentsRequiredToBeUniform.S=], add an edge from [=RequiredToBeUniform.S=] to *Vout*(*call*)

Note: Refer to [[#func-var-value-analysis]] for the definition of *Vout*(*call*).

Most built-in functions have tags of:
- A [=call site tag=] of [=CallSiteNoRestriction=].
- A [=function tag=] of [=NoRestriction=].
- For each parameter:
    - a [=parameter tag=] of [=ParameterNoRestriction=].
    - a [=parameter return tag=] of [=ParameterReturnContentsRequiredToBeUniform=].

Here is the list of exceptions:
- A call to a function in [[#sync-builtin-functions]]:
    - Has a [=function tag=] of [=NoRestriction=].
    - Has a [=call site tag=] of [=CallSiteRequiredToBeUniform.S|CallSiteRequiredToBeUniform.error=], with [=potential-trigger-set=]
        consisting of an unnamed [=diagnostic/triggering rule=].
        - Note: The triggering rule has no name, and so it cannot be filtered.
    - Additionally for the case of a call to [[#workgroupUniformLoad-builtin|workgroupUniformLoad]],
        the parameter `p` has a [=parameter tag=] of [=ParameterRequiredToBeUniform.S|ParameterRequiredToBeUniform.error=],
        with [=potential-trigger-set=] consisting of an unnamed [=diagnostic/triggering rule=].
- A call to a function in
    [[#derivative-builtin-functions]], [[#texturesample]], [[#texturesamplebias]], and [[#texturesamplecompare]]:
    - Has a [=function tag=] of [=ReturnValueMayBeNonUniform=].
    - Has a [=call site tag=] as follows:
        - Let *DF* be the [=nearest enclosing diagnostic filter=] for the call site location and triggering rule [=trigger/derivative_uniformity=]
        - If *DF* exists, then let *S* be the *DF*'s new severity parameter.
            - If *S* is the severity [=severity/off=], the call site tag is [=CallSiteNoRestriction=].
            - Otherwise the call site tag is [=CallSiteRequiredToBeUniform.S=], with [=potential-trigger-set=]
                consisting of a [=trigger/derivative_uniformity=] element.
        - If there is no such *DF*,
            the call site tag is [=CallSiteRequiredToBeUniform.S|CallSiteRequiredToBeUniform.error=], with [=potential-trigger-set=]
            consisting of a [=trigger/derivative_uniformity=] element.
- A call to [[#textureload]]:
    - Has a [=call site tag=] of [=CallSiteNoRestriction=]
    - Has a [=function tag=] as follows:
        - [=ReturnValueMayBeNonUniform=] if the argument corresponding to the `t` parameter
            is a [=type/read-write storage texture=]
        - [=NoRestriction=] otherwise


Note: A WGSL implementation will ensure that if control flow prior to a
function call is [=uniform control flow|uniform=], it will also be uniform
after the function call.

### Uniformity Rules for Expressions ### {#uniformity-expressions}

The rules for analyzing expressions take as argument both the expression itself and the node corresponding to control flow at the beginning of it (which we'll note "CF" below) and return the following:

* A node corresponding to control flow at the exit of it
* A node corresponding to its value
* A set of new nodes and edges to add to the graph

<table class='data'>
  <caption>Uniformity rules for [=RHSValue=] expressions</caption>
  <thead>
    <tr><th>Expression<th>New nodes<th>Recursive analyses<th>Resulting control flow node, value node<th>New edges
  </thead>
  <tr><td class="nowrap">*e1* || *e2*
      <td rowspan=2>
      <td rowspan=2 class="nowrap">(*CF*, *e1*) => (*CF1*, *V1*)<br>
          (*V1*, *e2*) => (*CF2*, *V2*)
      <td rowspan=2 class="nowrap">*CF*, *V2*
      <td rowspan=2>
  <tr><td class="nowrap">*e1* && *e2*
  <tr><td class="nowrap">Literal
      <td>
      <td>
      <td class="nowrap">*CF*, *CF*
      <td>
   <tr><td>identifier [=resolves|resolving=] to function-scope variable "x",
      where the identifier appears as the [=root identifier=] of a [=memory view=]
      expression, *MVE*, and the [=load rule=] is invoked on *MVE* during
      [=type checking=]
      <td>*Result*
      <td class>*X* is the node corresponding to the value of "x" at the input to the statement containing this expression
      <td class="nowrap">*CF*, *Result*
      <td class>*Result* -> {*CF*, *X*}

      Note: *X* is equivalent to *Vout*(*prev*) for "x"<br>
      (see [[#func-var-value-analysis]])
   <tr><td>identifier [=resolves|resolving=] to function-scope variable "x",
      where "x" is the desugared pointer parameter *i*, and
      where the identifier appears as the [=root identifier=] of a [=memory view=]
      expression, *MVE*, and the [=load rule=] is not invoked on *MVE* during
      [=type checking=]
      <td>
      <td class>
      <td class="nowrap">*CF*, [=param_i=]
      <td class>
   <tr><td>identifier [=resolves|resolving=] to function-scope variable "x",
      where the identifier appears as the [=root identifier=] of a [=memory view=]
      expression, *MVE*, and the [=load rule=] is not invoked on *MVE* during
      [=type checking=]
      <td>
      <td class>
      <td class="nowrap">*CF*, *CF*
      <td class>
   <tr><td>identifier [=resolves|resolving=] to [=const-declaration=], [=override-declaration=],
      [=let-declaration=], or non-built-in [=formal parameter=] of [=pointer type|non-pointer type=] "x"
      <td>*Result*
      <td>*X* is the node corresponding to "x"
      <td class="nowrap">*CF*, *Result*
      <td class="nowrap">*Result* -> {*CF*, *X*}
   <tr><td>identifier [=resolves|resolving=] to a [=formal parameter=] of
      [=pointer type=] in the [=address spaces/storage=], [=address spaces/workgroup=],
      or [=address spaces/private=] [=address spaces=] with a non-read-only
      [=access mode=] where the identifier appears as the [=root identifier=]
      of a [=memory view=] expression, *MVE*, and the [=load rule=] is invoked
      on *MVE* during [=type checking=]
      <td>
      <td>
      <td>*CF*, [=MayBeNonUniform=]
      <td>
   <tr><td>identifier [=resolves|resolving=] to a [=formal parameter=] of
      [=pointer type=] in the [=address spaces/storage=], [=address spaces/workgroup=],
      or [=address spaces/private=] [=address spaces=] with a non-read-only
      [=access mode=] where the identifier appears as the [=root identifier=]
      of a [=memory view=] expression, *MVE*, and the [=load rule=] is not
      invoked on *MVE* during [=type checking=]
      <td>
      <td>
      <td>*CF*, *CF*
      <td>
   <tr><td>identifier [=resolves|resolving=] to a [=formal parameter=] of
      [=pointer type=] in an [=address space=] other than [=address
      spaces/function=] with a read-only [=access mode=]
      <td>
      <td>
      <td>*CF*, *CF*
      <td>
   <tr><td>identifier [=resolves|resolving=] to uniform built-in value "x"
      <td>
      <td>
      <td class="nowrap">*CF*, *CF*
      <td>
   <tr><td>identifier [=resolves|resolving=] to non-uniform built-in value "x"
      <td>
      <td>
      <td class="nowrap">*CF*,<br>
      [=MayBeNonUniform=]
      <td>
   <tr><td>identifier [=resolves|resolving=] to read-only module-scope variable "x"
      <td>
      <td>
      <td class="nowrap">*CF*, *CF*
      <td>
   <tr><td>identifier [=resolves|resolving=] to non-read-only module-scope
      variable "x" where the identifier appears as the [=root identifier=] of a [=memory view=]
      expression, *MVE*, and the [=load rule=] is invoked on *MVE* during
      [=type checking=]
      <td>
      <td>
      <td class="nowrap">*CF*,<br>
      [=MayBeNonUniform=]
      <td>
   <tr><td>identifier [=resolves|resolving=] to non-read-only module-scope
      variable "x" where the identifier appears as the [=root identifier=] of a [=memory view=]
      expression, *MVE*, and the [=load rule=] is not invoked on *MVE* during
      [=type checking=]
      <td>
      <td>
      <td class="nowrap">*CF*,*CF*
      <td>
   <tr><td class="nowrap">*op* *e*,<br> where *op* is a unary operator
      <td rowspan=2>
      <td rowspan=2 class="nowrap">(*CF*, *e*) => (*CF'*, *V*)
      <td rowspan=2 class="nowrap">*CF'*, *V*
      <td rowspan=2>
   <tr><td class="nowrap">*e*.field
   <tr><td>*e1* *op* *e2*,<br> where *op* is a non-short-circuiting binary operator
      <td rowspan=2> *Result*
      <td rowspan=2 class="nowrap">(*CF*, *e1*) => (*CF1*, *V1*)<br>
          (*CF1*, *e2*) => (*CF2*, *V2*)
      <td rowspan=2 class="nowrap">*CF2*, *Result*
      <td rowspan=2 class="nowrap">*Result* -> {*V1*, *V2*}
   <tr><td class="nowrap">e1[e2]
</table>

The following built-in input variables are considered uniform:
- [=built-in values/workgroup_id=]
- [=built-in values/num_workgroups=]

All other ones (see [=built-in values=]) are considered non-uniform.

Note: An author should avoid grouping the uniform built-in values together with
other non-uniform inputs because the analysis does not analyze the [=components=]
of a [=composite=] type separately.

<table class='data'>
  <caption>Uniformity rules for [=LHSValue=] expressions</caption>
  <thead>
    <tr><th>Expression<th>New nodes<th>Recursive analyses<th>Resulting control flow node, variable node<th>New edges
  </thead>
   <tr><td>identifier [=resolves|resolving=] to function-scope variable "x"
      <td>*Result*
      <td>*X* is the node corresponding to the value of "x" at the output of the statement containing this expression.
      <td class="nowrap">*CF*, *Result*
      <td class>*Result* -> {*CF*, *X*}

      Note: *X* is equivalent to *Vin*(*next*) for "x"<br>
      (see [[#func-var-value-analysis]])
  <tr><td>identifier [=resolves|resolving=] to
          [=const-declaration=], [=override-declaration=], [=let-declaration=], or [=formal parameter=] "x"
      <td>
      <td>*X* is the node corresponding to "x"
      <td class="nowrap">*CF*, *X*
      <td>
  <tr><td>identifier [=resolves|resolving=] to module-scope variable "x"
      <td>
      <td>
      <td class="nowrap">*CF*,<br>
      [=MayBeNonUniform=]
      <td>
  <tr><td class="nowrap">*e*.field
      <td rowspan=3>
      <td class="nowrap" rowspan=3>[=LHSValue=]: (*CF*, *e*) => (*CF1*, *L1*)
      <td class="nowrap" rowspan=3>*CF1*, *L1*
      <td rowspan=3>
  <tr><td class="nowrap">**e*
  <tr><td class="nowrap">&*e*
  <tr><td class="nowrap">*e1*[*e2*]
      <td>
      <td class="nowrap">[=LHSValue=]: (*CF*, *e1*) => (*CF1*, *L1*)<br>
          (*CF1*, *e2*) => (*CF2*, *V2*)
      <td class="nowrap">*CF2*, *L1*
      <td class="nowrap">*L1* -> *V2*
</table>

### Annotating the Uniformity of Every Point in the Control-flow ### {#uniformity-optional-diagnosis-mode}

This entire subsection is non-normative.

If implementers want to provide developers with a diagnostic mode that shows for each point in the control-flow of the entire shader whether it is uniform or not (and thus whether it would be valid to call a function that requires uniformity there), we suggest the following:
- Run the (mandatory, normative) analysis described in the previous subsections, keeping the graph for every function.
- Reverse all edges in all of those graphs
- Go through each function, starting with the entry point and never visiting a function before having visited all of its callers:
    - Add an edge from [=MayBeNonUniform=] to every argument that was non-uniform in at least one caller.
    - Add an edge from [=MayBeNonUniform=] to [=CF_start=] if the function was called in non-uniform control-flow in at least one caller.
    - Look at which nodes are reachable from [=MayBeNonUniform=]. Every node visited is an expression or point in the control-flow whose uniformity cannot be proven by the analysis.

Any node which is not visited by these reachability analyses can be proven to be uniform by the analysis (and so it would be safe to call a derivative or similar function there).

Note: The bottom-up analysis is still required, as it lets us know what edges to add to the graphs when encountering calls.

### Examples ### {#uniformity-examples}

The graphs in the subsequent example use the following conventions for nodes:
* Rectangles represent value nodes.
* Rounded  rectangles represent control flow nodes.

#### Invalid `textureSample` Function Call #### {#uniformity-example1}

This example shows an invalid use of a [[#texturesample|textureSample]]
built-in function call.
The function call is made within an if statement whose condition depends on a
non-uniform value (i.e. the built-in value `position`).
The invalid dependency chain is highlighted in red.

<div class='example wgsl' heading='WGSL invalid textureSample'>
  <xmp highlight=wgsl>
    @group(0) @binding(0) var t : texture_2d<f32>;
    @group(0) @binding(1) var s : sampler;

    @fragment
    fn main(@builtin(position) pos : vec4<f32>) {
      if (pos.x < 0.5) {
        // Invalid textureSample function call.
        _ = textureSample(t, s, pos.xy);
      }
    }
  </xmp>
</div>

<div class=example1>
  <figure>
    <figcaption>Uniformity graph</figcaption>
    <object type="image/svg+xml" data="img/uniformity_1.mmd.svg"></object>
  </figure>
</div>

The example also shows that uniformity of the control flow after the if
statement is the same as the uniformity prior to the if statement (CF_return
being connected to [=CF_start=]).
That is, the control flow is once again uniform after the if statement (because
it is guaranteed to start as uniform control flow at the beginning of the entry
point).
If the `textureSample` function call had been moved outside the if statement
the program would have been valid.
Likewise, if the condition of the if statement were a uniform value (e.g. each
invocation read the same value from a [=uniform buffer=]), the program would
also have been valid.

#### Function-scope Variable Uniformity #### {#uniformity-example2}

This example shows both a valid and an invalid
[[#sync-builtin-functions|barrier]] function call that depend on the value of a
function-scope variable.
The `workgroupBarrier` is invalid because the value of `x` is derived from the
mutable module-scope variable `a`.
The `storageBarrier` is valid because the value of `x` is derived from the
immutable module-scope variable `b`.
This example highlights the [[#func-var-value-analysis|value analysis']]
ability to separate different periods of uniformity in a function-scope
variable's lifetime.
This example also clearly shows that control flow becomes uniform again after
the end of the first [=statement/if=] statement.
We know this because that section of the graph is independent from the second
if statement.

<div class='example wgsl' heading='WGSL using function variable'>
  <xmp highlight=wgsl>
    @group(0) @binding(0) var<storage, read_write> a : i32;
    @group(0) @binding(1) var<uniform> b : i32;

    @compute @workgroup_size(16,1,1)
    fn main() {
      var x : i32;
      x = a;
      if x > 0 {
        // Invalid barrier function call.
        workgroupBarrier();
      }
      x = b;
      if x < 0 {
        // Valid barrier function call.
        storageBarrier();
      }
    }
  </xmp>
</div>

<div class=example2>
  <figure>
    <figcaption>Uniformity graph</figcaption>
    <object type="image/svg+xml" data="img/uniformity_2.mmd.svg"></object>
  </figure>
</div>

Note: The subgraphs are only included in the example for ease of understanding.


#### Composite Value Analysis Limitations #### {#uniformity-example3}

One limitation of the uniformity analysis is that it does not track the
[=components=] of a [=composite=] value independently.
That is, any non-uniform component value [=behavioral requirement|will=] cause
the analysis to treat the entire composite value as non-uniform.
This example illustrates this issue and a potential workaround that shader
authors can employ to avoid this limitation.

<div class='example wgsl' heading='Invalid composite value WGSL'>
  <xmp highlight=wgsl>
    struct Inputs {
      // workgroup_id is a uniform built-in value.
      @builtin(workgroup_id) wgid : vec3<u32>,
      // local_invocation_index is a non-uniform built-in value.
      @builtin(local_invocation_index) lid : u32
    }

    @compute @workgroup_size(16,1,1)
    fn main(inputs : Inputs) {
      // This comparison is always uniform,
      // but the analysis cannot determine that.
      if inputs.wgid.x == 1 {
        workgroupBarrier();
      }
    }
  </xmp>
</div>

<div class=example2>
  <figure>
    <figcaption>Invalid uniformity graph</figcaption>
    <object type="image/svg+xml" data="img/uniformity_3.mmd.svg"></object>
  </figure>
</div>

The easiest way to work around this limitation of the analysis is to split the
composite up so that values that are known to be uniform are separate from
value that are known to be non-uniform.
In the alternative WGSL below, splitting the two built-in values into separate
parameters satisfies the uniformity analysis.
This can be seen by the lack of a path from [=RequiredToBeUniform.S=] to
[=MayBeNonUniform=] in the graph.

<div class='example wgsl' heading='Valid alternative WGSL'>
  <xmp highlight=wgsl>
    @compute @workgroup_size(16,1,1)
    fn main(@builtin(workgroup_id) wgid : vec3<u32>,
            @builtin(local_invocation_index) lid : u32) {
      // The uniformity analysis can now correctly determine this comparison is
      // always uniform.
      if wgid.x == 1 {
        // Valid barrier function call.
        workgroupBarrier();
      }
    }
  </xmp>
</div>

<div class=example3>
  <figure>
    <figcaption>Valid alternative uniformity graph</figcaption>
    <object type="image/svg+xml" data="img/uniformity_3b.mmd.svg"></object>
  </figure>
</div>

#### Uniformity in a Loop #### {#uniformity-example4}

In this example, there is an invalid `workgroupBarrier` function call in a
loop.
The non-uniform built-in value `local_invocation_index` is the ultimate cause
despite the fact that it appears after the barrier in the loop.
This occurs, because on later iterations some of the invocations in the
workgroup will have exited the loop prematurely while others attempt to execute
the barrier.
The analysis models the inter-iteration dependencies as an edge, where the control
at the start of the loop body (CF_loop_body) depends on the control flow at the
end of the loop body (CF_after_if).

<div class='example wgsl' heading='Loop uniformity WGSL'>
  <xmp highlight=wgsl>
    @compute @workgroup_size(16,1,1)
    fn main(@builtin(local_invocation_index) lid : u32) {
      for (var i = 0u; i < 10; i++) {
        workgroupBarrier();
        if (lid + i) > 7 {
          break;
        }
      }
    }
  </xmp>
</div>

<div class=example4>
  <figure>
    <figcaption>Uniformity graph</figcaption>
    <object type="image/svg+xml" data="img/uniformity_4.mmd.svg"></object>
  </figure>
</div>

#### User-defined Function Calls #### {#uniformity-example5}

This example is modification of the [[#uniformity-example1|first example]], but
uses a user-defined function call.
The analysis sets the [=parameter return tag=] of both parameters of `scale` as
[=ParameterReturnContentsRequiredToBeUniform=].
This leads to the path in `main` between the return value of the `scale`
function call and the `position` built-in value.
That path is a subpath of the overall invalid path from [=RequiredToBeUniform.S=] to
[=MayBeNonUniform=].

<div class='example wgsl' heading='User-defined function call uniformity WGSL'>
  <xmp highlight=wgsl>
    fn scale(in1 : f32, in2 : f32) -> f32 {
      let v = in1 / in2;
      return v;
    }

    @group(0) @binding(0) var t : texture_2d<f32>;
    @group(0) @binding(1) var s : sampler;

    @fragment
    fn main(@builtin(position) pos : vec4<f32>) {
      let tmp = scale(pos.x, 0.5);
      if tmp > 1.0 {
        _ = textureSample(t, s, pos.xy);
      }
    }
  </xmp>
</div>

<div class=example5>
  <figure>
    <figcaption>Uniformity graph for scale</figcaption>
    <object type="image/svg+xml" data="img/uniformity_5scale.mmd.svg"></object>
  </figure>

  <figure>
    <figcaption>Uniformity graph for main</figcaption>
    <object type="image/svg+xml" data="img/uniformity_5main.mmd.svg"></object>
  </figure>
</div>

Note: The subgraphs are only included in the example for ease of understanding.

## Compute Shaders and Workgroups ## {#compute-shader-workgroups}

A <dfn noexport for="compute shader stage">workgroup</dfn> is a set of invocations which
concurrently execute a [=compute shader stage=] [=entry point=],
and share access to shader variables in the [=address spaces/workgroup=] address space.

The <dfn noexport>workgroup grid</dfn> for a compute shader is the set of points
with integer coordinates *(i,j,k)* with:

*  0 &leq; i &lt; workgroup_size_x
*  0 &leq; j &lt; workgroup_size_y
*  0 &leq; k &lt; workgroup_size_z

where *(workgroup_size_x, workgroup_size_y, workgroup_size_z)* is
the value specified for the [=attribute/workgroup_size=] attribute of the
entry point.

There is exactly one invocation in a workgroup for each point in the workgroup grid.

An invocation's <dfn noexport>local invocation ID</dfn> is the coordinate
triple (i,j,k) for the invocation's corresponding workgroup grid point.

When an invocation has [=local invocation ID=], then its
<dfn noexport>local invocation index</dfn> is

  i +
  (j * workgroup_size_x) +
  (k * workgroup_size_x * workgroup_size_y)

<p algorithm="local index range">Note that if a workgroup has |W| invocations,
then each invocation |I| the workgroup has a unique local invocation index |L|(|I|)
such that 0 &le; |L|(|I|) &lt; |W|,
and that entire range is covered.</p>

A compute shader begins execution when a WebGPU implementation
removes a dispatch command from a queue and begins the specified work on the GPU.
The dispatch command specifies a <dfn noexport>dispatch size</dfn>,
which is an integer triple (<dfn>group_count_x</dfn>, <dfn>group_count_y</dfn>, <dfn>group_count_z</dfn>)
indicating the number of workgroups to be executed, as described in the following.

The <dfn noexport>compute shader grid</dfn> for a particular dispatch
is the set of points with integer coordinates *(CSi,CSj,CSk)* with:

*  0 &leq; CSi &lt; workgroup_size_x &times; group_count_x
*  0 &leq; CSj &lt; workgroup_size_y &times; group_count_y
*  0 &leq; CSk &lt; workgroup_size_z &times; group_count_z

where *workgroup_size_x*,
*workgroup_size_y*, and
*workgroup_size_z* are as above for the compute shader entry point.

The work to be performed by a compute shader dispatch is to execute exactly one
invocation of the entry point for each point in the compute shader grid.

An invocation's <dfn noexport>global invocation ID</dfn> is the coordinate
triple for the invocation's corresponding compute shader grid point.

The invocations are organized into workgroups, so that each invocation's
[=global invocation ID=] *(CSi, CSj, CSk)* maps to
a single workgroup, identified by <dfn noexport>workgroup ID</dfn>:

   ( &lfloor; *CSi* &div; workgroup_size_x &rfloor;,
     &lfloor; *CSj* &div; workgroup_size_y &rfloor;,
     &lfloor; *CSk* &div; workgroup_size_z &rfloor;)

and a single invocation within that workgroup, identified by [=local invocation ID=]:

   ( *CSi* mod workgroup_size_x ,
     *CSj* mod workgroup_size_y ,
     *CSk* mod workgroup_size_z ).

Note: Workgroup IDs span from (0,0,0) to ([=group_count_x=] - 1, [=group_count_y=] - 1, [=group_count_z=] - 1).

WebGPU provides no guarantees about:

* Whether invocations from different workgroups execute concurrently.
    That is, you cannot assume more than one workgroup executes at a time.
* Whether, once invocations from a workgroup begin executing, that other workgroups
    are blocked from execution.
    That is, you cannot assume that only one workgroup executes at a time.
    While a workgroup is executing, the implementation may choose to
    concurrently execute other workgroups as well, or other queued but unblocked work.
* Whether invocations from one particular workgroup begin executing before
    the invocations of another workgroup.
    That is, you cannot assume that workgroups are launched in a particular order.

## Fragment Shaders and Helper Invocations ## {#fragment-shaders-helper-invocations}

Invocations in the [=fragment shader stage=] are divided into 2x2 grids of
invocations with neighbouring [=built-in values/position|positions=] in the X and Y dimensions.
Each of these grids is referred to as a <dfn noexport>quad</dfn>.
Quads can collaborate in some collective operations (see [[#derivatives]]).

Ordinarily, [[WebGPU#fragment-processing|fragment processing]] creates one
invocation of a fragment shader for each
[=RasterizationPoint=] produced by
[[WebGPU#rasterization|rasterization]].
Sometimes there may be insufficient RasterizationPoints to fully populate a
quad, for example at the edge of a graphics primitive.
When a quad has only 1, 2, or 3 invocations corresponding to
RasterizationPoints, fragment processing [=behavioral requirement|will=] create
a <dfn noexport>helper invocation</dfn> for each unpopulated position in the
quad.

Helper invocations do not have observable effects, except that they help
compute [[#derivatives|derivatives]].
As such, helper invocations are subject to the following restrictions:
* No [=write access|write accesses=] (see also [[#memory-operation]])
    [=behavioral requirement|will=] be performed on the [=address
    spaces/storage=] or [=address spaces/handle=] address spaces.
* [[#atomic-builtin-functions|Atomic built-in functions]] [=behavioral requirement|will=]
    return [=indeterminate value|indeterminate=] results.
* The [=Entry point=] [=return value=] [=behavioral requirement|will=] not be further processed
    downstream in the [=GPURenderPipeline=].

If all of the invocations in a quad become helper invocations (e.g. due to
executing a [=statement/discard=] statement), execution of the quad may be
terminated; however, such termination is not considered to produce [=uniform
control flow|non-uniform control flow=].

## Collective Operations ## {#collective-operations}

### Barriers ### {#barrier}

A barrier is a [[#sync-builtin-functions|synchronization built-in function]]
that orders memory operations in a program.
A <dfn noexport>control barrier</dfn> is executed by all invocations in the
same [=compute shader stage/workgroup=] as if it were executed concurrently.
As such, control barriers [=shader-creation error|must=] only be executed in [=uniform control flow=] in a
[=compute shader stage|compute=] shader.

### Derivatives ### {#derivatives}

A <dfn noexport>partial derivative</dfn> is the rate of change of a value along an axis.
Fragment shader invocations within the same [=quad=] collaborate to compute
approximate partial derivatives.

The <dfn noexport>builtin functions that compute a derivative</dfn> are:
* [[#texturesample|textureSample]], [[#texturesamplebias|textureSampleBias]], and [[#texturesamplecompare|textureSampleCompare]]
* [[#dpdx-builtin|dpdx]], [[#dpdxCoarse-builtin|dpdxCoarse]], and [[#dpdxFine-builtin|dpdxFine]]
* [[#dpdy-builtin|dpdy]], [[#dpdyCoarse-builtin|dpdyCoarse]], and [[#dpdyFine-builtin|dpdyFine]]
* [[#fwidth-builtin|fwidth]], [[#fwidthCoarse-builtin|fwidthCoarse]], and [[#fwidthFine-builtin|fwidthFine]]

Partial derivatives of the *fragment coordinate* are computed implicitly as part
of operation of the following built-in functions:
* [[#texturesample|textureSample]],
* [[#texturesamplebias|textureSampleBias]], and
* [[#texturesamplecompare|textureSampleCompare]].

For these, the derivatives help determine the mip levels of texels to be sampled, or in the case of
`textureSampleCompare`, sampled and compared against a reference value.

Partial derivatives of *invocation-specified* values are computed by the
built-in functions described in [[#derivative-builtin-functions]]:
* [[#dpdx-builtin|dpdx]], [[#dpdxCoarse-builtin|dpdxCoarse]], and [[#dpdxFine-builtin|dpdxFine]] compute partial derivatives along the x axis.
* [[#dpdy-builtin|dpdy]], [[#dpdyCoarse-builtin|dpdyCoarse]], and [[#dpdyFine-builtin|dpdyFine]] compute partial derivatives along the y axis.
* [[#fwidth-builtin|fwidth]], [[#fwidthCoarse-builtin|fwidthCoarse]], and [[#fwidthFine-builtin|fwidthFine]]
    compute the Manhattan metric over the associated x and y partial derivatives.

Because neighbouring invocations collaborate to compute derivatives, these
functions should only be invoked in [=uniform control flow=] in a fragment shader.
For each call to one of these functions, a [=trigger/derivative_uniformity=] [=diagnostic=] is triggered if
[[#uniformity|uniformity analysis]] cannot prove the call occurs in uniform control flow.

If one of these functions is called in non-uniform control flow, then the result is an [=indeterminate value=].

## Floating Point Evaluation ## {#floating-point-evaluation}

WGSL follows the [[!IEEE-754|IEEE-754]] standard for floating point computation with
the following differences:
* No rounding mode is specified. An implementation may round a value up or down.
* No floating point exceptions are generated.
    * A floating point operation in WGSL [=behavioral requirement|will=] produce an intermediate result
        according to IEEE-754 rules, but exceptions mandated by IEEE-754 will map to different
        behaviors depending on whether the expression is
        a [=const-expression=], an [=override-expression=], or a [=runtime expression=].
    * IEEE-754 defines five kinds of exceptions:
        * Invalid operation. These operations yield a NaN.  An example of an invalid operation is 0 &times; &infin;.
        * Division by zero. This occurs when an operation on finite operands is defined as having an exact infinite result.
            Examples are 1 &divide; 0, and log(0).
        * Overflow. See [[#floating-point-overflow]].
        * Underflow. This occurs when the rounded or unrounded result is subnormal.
        * Inexact. This occurs when the rounded result is different from the intermediate result,
            or when overflow occurs.
    * Consider an operation on finite operands.
        The operation produces overflow, infinity, or a NaN if and only if IEEE-754 would require the
        operation to signal an invalid operation, division-by-zero, or overflow exception.
* Signaling NaNs may not be generated.
    Any signaling NaN may be converted to a quiet NaN.
* Overflow, infinities, and NaNs generated before runtime are errors.
    * [=Const-expressions=] and [=override-expressions=] over finite values
        [=behavioral requirement|will=] generate overflow, infinities, and NaNs
        as intermediate values, following IEEE-754 rules.
        * Note: This rule requires implementations to reliably detect overflow, infinities, and NaNs
            to within accuracy limits for these kinds of expressions, so that errors can be generated consistently.
    * A [=shader-creation error=] results if any [=const-expression=] of
        floating-point type overflows or evaluates to NaN or infinity.
    * A [=pipeline-creation error=] results if any [=override-expression=] of
        floating-point type overflows or evaluates to NaN or infinity.
* Implementations may assume that overflow, infinities, and NaNs are not present at runtime.
    * In such an implementation, if the intermediate result of evaluating a [=runtime expression=] overflows,
        or yields infinity or a NaN, the final result [=behavioral requirement|will=] be
        an [=indeterminate value=] of the target type.
    * Note: This means some functions (e.g. `min` and `max`)
        may not return the expected result due to optimizations about the presence
        of NaNs and infinities.
* Implementations may ignore the sign of a zero.
    That is, a zero with a positive sign may behave like a zero a with a negative sign, and vice versa.
* To <dfn noexport title="flushed to zero">flush to zero</dfn> is to replace a denormalized value for a floating point type
    with a zero value of that type.
    * Any inputs or outputs of operations listed in [[#floating-point-accuracy]] may be flushed to zero.
    * Additionally, intermediate values of operations listed in
        [[#bit-reinterp-builtin-functions]], [[#pack-builtin-functions]], or
        [[#unpack-builtin-functions]] may be flushed to zero.
    * Other operations are required to preserve denormalized numbers.
* The accuracy of operations is given in [[#floating-point-accuracy]].

### Floating Point Overflow ### {#floating-point-overflow}

Overflowing computations can round to infinity or to the
nearest finite value.
The outcome depends on the magnitude of the overflowing value and on whether
evaluation occurs during shader execution.

For a floating point type *T*, define *MAX(T)* as the largest positive finite value of *T*,
and 2<sup>*EMAX(T)*</sup> as the largest power of 2 representable by *T*.
In particular, EMAX([=f32=]) = 127, and EMAX([=f16=]) = 15.

Let *X* be an infinite-precision intermediate result from a floating point computation.
The final value of the expression is determined in two stages, via intermediate values *X'* and *X''* as follows:

From *X*, compute *X'* in *T* by rounding:
* If *X* is in the finite range of *T* then *X'* is the result of rounding *X* up or down.
* If *X* is NaN, then *X'* is NaN.
* If *MAX(T)* &lt; *X* &lt; 2<sup>*EMAX(T)+1*</sup>, then either rounding direction is used: *X'* is *MAX(T)* or &plus;&infin;.
* If 2<sup>*EMAX(T)+1*</sup> &le; *X*, then *X'* = &plus;&infin;.
    * Note: This matches the [[!IEEE-754|IEEE-754]] rule.
* If &minus;*MAX(T)* &gt; *X* &gt; &minus;2<sup>*EMAX(T)+1*</sup>, then either rounding direction is used: *X'* is &minus;*MAX(T)* or &minus;&infin;.
* If &minus;2<sup>*EMAX(T)+1*</sup> &ge; *X*, then *X'* = &minus;&infin;.
    * Note: This matches the IEEE-754 rule.

From *X'*, compute the final value of the expression, *X''*, or detect a program error:
* If *X'* is infinity or NaN, then:
    * If the expression is a [=const-expression=], generate a [=shader-creation error=].
    * If the expression is a [=override-expression=], generate a [=pipeline-creation error=].
    * Otherwise the expression is a [=runtime expression=] and *X''* is an [=indeterminate value=].
* Otherwise *X''* = *X'*.


### Floating Point Accuracy ### {#floating-point-accuracy}

<div algorithm="correctly rounded">
Let |x| be the exact real-valued or infinite result of an operation when computed with unbounded precision.
The <dfn>correctly rounded</dfn> result of the operation for floating point type |T| is:
* |x|, when |x| is in |T|,
* Otherwise:
    * the smallest value in |T| greater than |x|, or
    * the largest value in |T| less than |x|.

</div>

That is, the result may be rounded up or down:
WGSL does not specify a rounding mode.

Note: Floating point types include positive and negative infinity, so
the correctly rounded result may be finite or infinite.

The units in the last place, <dfn noexport>ULP</dfn>, for a floating point
number `x` is defined as follows [[!Muller2005]]:
* If `x` is in the finite range of the floating point type, then ULP(x) is
    the minimum distance between two non-equal, finite floating point numbers
    `a` and `b` such that `a` &le; `x` &le; `b` (i.e. `ulp(x) =
    min`<sub>`a,b`</sub>`|b - a|`).
* Otherwise, ULP(x) is `|b - a|` where `b` and `a` are the largest and second-largest
    representable finite floating point values.

The accuracy of an operation is provided among five
possibilities:
* Correct result (for non-floating point result values).
* [=Correctly rounded=].
* An absolute error bound.
* A relative error bound expressed as [=ULP=].
* An expression that the accuracy is <dfn noexport>inherited from</dfn>.
    That is, the accuracy of the operation is defined as the accuracy of evaluating the given WGSL expression.
    The given expression is only one valid implementation of the function.
    A WebGPU implementation may implement the operation differently, with better accuracy
    or with greater tolerance for extreme inputs.
    Additionally, an implementation may treat intermediate results as subject to the rules for
    floating-point evaluation (e.g. they may be rounded and/or [=flush to zero|flushed-to-zero=]).

When the accuracy for an operation is specified over an input range,
the accuracy is undefined for input values outside that range.

If an allowed result is outside the finite range of the result type, then
the rules in [[#floating-point-overflow]] apply.

#### Accuracy of Concrete Floating Point Expressions #### {#concrete-float-accuracy}

<table class='data'>
  <caption>Accuracy of concrete floating point operations</caption>
  <thead>
    <tr><th>Expression<th>Accuracy for f32<th>Accuracy for f16
  </thead>

  <tr><td>`x + y`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`x - y`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`x * y`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`x / y`<td>2.5 ULP for `|y|` in the range [2<sup>-126</sup>, 2<sup>126</sup>]<td>2.5 ULP for `|y|` in the range [2<sup>-14</sup>, 2<sup>14</sup>]
  <tr><td>`x % y`<td colspan=2 style="text-align:left;">Inherited from `x - y * trunc(x/y)`
  <tr><td>`-x`<td colspan=2 style="text-align:left;">Correctly rounded

  <tr><td>`x == y`<td colspan=2 style="text-align:left;">Correct result
  <tr><td>`x != y`<td colspan=2 style="text-align:left;">Correct result
  <tr><td>`x < y`<td colspan=2 style="text-align:left;">Correct result
  <tr><td>`x <= y`<td colspan=2 style="text-align:left;">Correct result
  <tr><td>`x > y`<td colspan=2 style="text-align:left;">Correct result
  <tr><td>`x >= y`<td colspan=2 style="text-align:left;">Correct result
</table>

<table class='data'>
  <caption>Accuracy of concrete floating point built-in functions</caption>
  <thead>
    <tr><th>Built-in Function<th>Accuracy for f32<th>Accuracy for f16
  </thead>

  <tr><td>`abs(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`acos(x)`<td>
       The worse of:
       * Absolute error 6.77&times;10<sup>-5</sup>
       * Inherited from `atan2(sqrt(1.0 - x * x), x)`

      <td>The worse of:
       * Absolute error 3.91&times;10<sup>-3</sup>
       * Inherited from `atan2(sqrt(1.0 - x * x), x)`
          <p>TODO: check this with conformance tests
  <tr><td>`acosh(x)`<td colspan=2 style="text-align:left;">Inherited from `log(x + sqrt(x * x - 1.0))`
  <tr><td>`asin(x)`<td>
       The worse of:
       * Absolute error 6.81&times;10<sup>-5</sup>
       * Inherited from `atan2(x, sqrt(1.0 - x * x))`

      <td>The worse of:
       * Absolute error 3.91&times;10<sup>-3</sup>
       * Inherited from `atan2(x, sqrt(1.0 - x * x))`
          <p>TODO: check this with conformance tests
  <tr><td>`asinh(x)`<td colspan=2 style="text-align:left;">Inherited from `log(x + sqrt(x * x + 1.0))`
  <tr><td>`atan(x)`<td>4096 ULP<td>5 ULP
  <tr><td>`atan2(y, x)`<td>4096 ULP for `|x|` in the range [2<sup>-126</sup>, 2<sup>126</sup>], and `y` is finite and normal<td>5 ULP for `|x|` in the range [2<sup>-14</sup>, 2<sup>14</sup>], and `y` is finite and normal
  <tr><td>`atanh(x)`<td colspan=2 style="text-align:left;">Inherited from `log( (1.0 + x) / (1.0 - x) ) * 0.5`
  <tr><td>`ceil(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`clamp(x,low,high)`<td colspan=2 style="text-align:left;">Correctly rounded.

    The infinitely precise result is computed as either `min(max(x,low),high)`, or with a median-of-3-values formulation.
    These may differ when `low > high`.

    If `x` and either `low` or `high` are denormalized, the result may be any of the denormalized values.
    This follows from the possible results from the `min` and `max` functions on denormalized inputs.
  <tr><td>`cos(x)`
      <td>Absolute error at most 2<sup>-11</sup> when `x` is in the interval [-&pi;, &pi;]
      <td>Absolute error at most 2<sup>-7</sup> when `x` is in the interval [-&pi;, &pi;]
  <tr><td>`cosh(x)`<td colspan=2 style="text-align:left;">Inherited from `(exp(x) + exp(-x)) * 0.5`
  <tr><td>`cross(x, y)`<td colspan=2 style="text-align:left;">Inherited from `(x[i] * y[j] - x[j] * y[i])`
  <tr><td>`degrees(x)`<td colspan=2 style="text-align:left;">Inherited from `x * 57.295779513082322865`
  <tr><td>`determinant(m:mat2x2<T>)`<br>
          `determinant(m:mat3x3<T>)`<br>
          `determinant(m:mat4x4<T>)`
     <td colspan=2 style="text-align:left;">Infinite ULP.

     <div class=note>
     <span class=marker>Note:</span>WebGPU implementations should provide a pragmatically useful determinant function.

     In ideal math, determinants are computed with add, subtract, and multiply operations.

     However, GPUs use floating point math, and GPU implementations of determinant
     favour speed and simplicity over robustness against overflow and error.

     For example, the naive computation of even a 2x2 determinant (`m[0][0] * m[1][1] - m[1][0] * m[0][1]`)
     fails to guard against catastrophic cancellation.
     Providing tighter error bounds for 2x2 determinants is the subject of relatively recent research [[Jeannerod2013]].
     The challenges compound quickly as matrix sizes increase.

     The lack of a finite error bound for determinants in WGSL reflects the same lack in underlying implementations.
     </div>
  <tr><td>`distance(x, y)`<td colspan=2 style="text-align:left;">Inherited from `length(x - y)`
  <tr><td>`dot(x, y)`<td colspan=2 style="text-align:left;">Inherited from sum of `x[i] * y[i]`
  <tr><td>`exp(x)`<td>`3 + 2 * |x|` ULP<td>`1 + 2 * |x|` ULP
  <tr><td>`exp2(x)`<td>`3 + 2 * |x|` ULP<td>`1 + 2 * |x|` ULP
  <tr><td class="nowrap">`faceForward(x, y, z)`<td colspan=2 style="text-align:left;">Inherited from `select(-x, x, dot(z, y) < 0.0)`
  <tr><td>`floor(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`fma(x, y, z)`<td colspan=2 style="text-align:left;">Inherited from `x * y + z`
  <tr><td>`fract(x)`<td colspan=2 style="text-align:left;">Inherited from `x - floor(x)`
  <tr><td>`frexp(x)`<td colspan=2 style="text-align:left;">Correctly rounded, when `x` is zero or normal.
  <tr><td>`inverseSqrt(x)`<td colspan=2 style="text-align:left;">2 ULP
  <tr><td>`ldexp(x, y)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`length(x)`<td colspan=2 style="text-align:left;">Inherited from `sqrt(dot(x, x))` in the vector case, and `sqrt(x*x)` in the scalar case.
  <tr><td>`log(x)`
      <td>Absolute error at most 2<sup>-21</sup> when `x` is in the interval [0.5, 2.0].<br>
          3 ULP when `x` is outside the interval [0.5, 2.0].<br>
      <td>Absolute error at most 2<sup>-7</sup> when `x` is in the interval [0.5, 2.0].<br>
          3 ULP when `x` is outside the interval [0.5, 2.0].<br>
  <tr><td>`log2(x)`
      <td>Absolute error at most 2<sup>-21</sup> when `x` is in the interval [0.5, 2.0].<br>
          3 ULP when `x` is outside the interval [0.5, 2.0].<br>
      <td>Absolute error at most 2<sup>-7</sup> when `x` is in the interval [0.5, 2.0].<br>
          3 ULP when `x` is outside the interval [0.5, 2.0].<br>
  <tr><td>`max(x, y)`<td colspan=2 style="text-align:left;">Correctly rounded
  <p>If both `x` and `y` are denormalized, the result may be either input.
  <tr><td>`min(x, y)`<td colspan=2 style="text-align:left;">Correctly rounded.
  <p>If both `x` and `y` are denormalized, the result may be either input.
  <tr><td>`mix(x, y, z)`<td colspan=2 style="text-align:left;">Inherited from `x * (1.0 - z) + y * z`
  <tr><td>`modf(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`normalize(x)`<td colspan=2 style="text-align:left;">Inherited from `x / length(x)`

  <tr><td>`pack4x8snorm(x)`<td colspan=2 style="text-align:left;">Correctly rounded intermediate value. Correct result.
  <tr><td>`pack4x8unorm(x)`<td colspan=2 style="text-align:left;">Correctly rounded intermediate value. Correct result.
  <tr><td>`pack2x16snorm(x)`<td colspan=2 style="text-align:left;">Correctly rounded intermediate value. Correct result.
  <tr><td>`pack2x16unorm(x)`<td colspan=2 style="text-align:left;">Correctly rounded intermediate value. Correct result.
  <tr><td>`pack2x16float(x)`<td colspan=2 style="text-align:left;">Correctly rounded intermediate value. Correct result.

  <tr><td>`pow(x, y)`<td colspan=2 style="text-align:left;">Inherited from `exp2(y * log2(x))`
  <tr><td>`quantizeToF16(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`radians(x)`<td colspan=2 style="text-align:left;">Inherited from `x * 0.017453292519943295474`
  <tr><td>`reflect(x, y)`<td colspan=2 style="text-align:left;">Inherited from `x - 2.0 * dot(x, y) * y`
  <tr><td>`refract(x, y, z)`<td colspan=2 style="text-align:left;">Inherited from `z * x - (z * dot(y, x) + sqrt(k)) * y`,<br>where `k = 1.0 - z * z * (1.0 - dot(y, x) * dot(y, x))`<br>If `k < 0.0` the result is precisely 0.0
  <tr><td>`round(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`sign(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`sin(x)`
      <td>Absolute error at most 2<sup>-11</sup> when `x` is in the interval [-&pi;, &pi;]
      <td>Absolute error at most 2<sup>-7</sup> when `x` is in the interval [-&pi;, &pi;]
  <tr><td>`sinh(x)`<td colspan=2 style="text-align:left;">Inherited from `(exp(x) - exp(-x)) * 0.5`
  <tr><td>`saturate(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`smoothstep(low, high, x)`<td colspan=2 style="text-align:left;">Inherited from `t * t * (3.0 - 2.0 * t)`,<br>where `t = clamp((x - low) / (high - low), 0.0, 1.0)`
  <tr><td>`sqrt(x)`<td colspan=2 style="text-align:left;">Inherited from `1.0 / inverseSqrt(x)`
  <tr><td>`step(edge, x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`tan(x)`<td colspan=2 style="text-align:left;">Inherited from `sin(x) / cos(x)`
  <tr><td>`tanh(x)`<td colspan=2 style="text-align:left;">Inherited from `sinh(x) / cosh(x)`
  <tr><td>`transpose(x)`<td colspan=2 style="text-align:left;">Correctly rounded
  <tr><td>`trunc(x)`<td colspan=2 style="text-align:left;">Correctly rounded

  <tr><td>`unpack4x8snorm(x)`<td>3 ULP<td>N/A
  <tr><td>`unpack4x8unorm(x)`<td>3 ULP<td>N/A
  <tr><td>`unpack2x16snorm(x)`<td>3 ULP<td>N/A
  <tr><td>`unpack2x16unorm(x)`<td>3 ULP<td>N/A
  <tr><td>`unpack2x16float(x)`<td>Correctly rounded<td>N/A

</table>

#### Accuracy of AbstractFloat Expressions #### {#abstract-float-accuracy}

The accuracy of an [=AbstractFloat=] operation is as follows:
* A correct result is required when the corresponding [=f32=] operation requires a correct result.
* A [=correctly rounded=] result is required when the corresponding [=f32=] operation requires a correctly rounded result.
* `fract(x)`'s error is inherited from `x - floor(x)`, where the intermediate calculations are performed as [=AbstractFloat=] operations.
* Otherwise, the error of the corresponding [=f32=] operation is an absolute error, a relative error, an error inherited
    from a potential implementation, or a combination of these.
    In this case the error of the [=AbstractFloat=] is unbounded.
    * However, the error of the [=AbstractFloat=] operation *should* be at most
        the error of the corresponding operation in [=f32=], in absolute terms.
    * This recommendation is meant to avoid surprises: the accuracy of
        an expression should not be *reduced* when changing its type from f32 to AbstractFloat.
    * The operation may be evaluated in a WebAssembly [[WASM-CORE-2]] or an ECMAScript [[ECMASCRIPT]]
        environment, and those specifications do not specify error bounds on many
        of the corresponding numeric computations.
        For example, ECMAScript specifies many floating point operations as being
        [[ECMASCRIPT#sec-terms-and-definitions-implementation-approximated|implementation-approximated]].
        Implementations are encouraged to strive to approximate the ideal, but
        no strict requirement is specified.

<div class=note algorithm="ulp translation">
<span class=marker>Note:</span>A given absolute error bound, when quantified as ULP,
depends critically on the underlying floating point type.

The [=ULP=] for an [=AbstractFloat=] value assumes
AbstractFloat is identical to the [[!IEEE-754|IEEE-754]] binary64 type.

One [=ULP=] for an f32 value is 2<sup>29</sup> times larger than 1 ULP for an IEEE 754 binary64 value,
since the significand in the binary64 format is 29 bits longer than the significand in the f32 type.

For example, suppose the true result value of an operation is |x|, but it is computed as <var>x'</var>.
If its error |x|-<var>x'</var> is 3 ULP in f32, then the same absolute error, |x|-<var>x'</var>,
is 3&middot;2<sup>29</sup> ULP in AbstractFloat.
</div>

### Reassociation and Fusion ### {#reassociation-and-fusion}

<dfn noexport>Reassociation</dfn> is the reordering of operations in an
expression such that the answer is the same if computed exactly. For example:
* `(a + b) + c` reassociates to `a + (b + c)`
* `(a - b) + c` reassociates to `(a + c) - b`
* `(a * b) / c` reassociates to `(a / c) * b`

However, the result may not be the same when computed in floating point.
The reassociated result may be inaccurate due to approximation, or may trigger
an overflow or NaN when computing intermediate results.

An implementation may reassociate operations.

An implementation may fuse operations if the transformed expression is
at least as accurate as the original formulation.
For example, some fused multiply-add implementations can be more accurate
than performing a multiply followed by an addition.

### Floating Point Conversion ### {#floating-point-conversion}

In this section, a floating point type may be any of:
* The [=f32=], [=f16=], and [=AbstractFloat=] types in WGSL.
* A hypothetical type corresponding to a binary format defined by the [[!IEEE-754|IEEE-754]]
    floating point standard.

Note: Recall that the [=f32=] WGSL type corresponds to the IEEE-754 binary32 format, and the [=f16=] WGSL type corresponds to the IEEE-754 binary16 format.

The <dfn noexport>scalar floating point to integral conversion</dfn> algorithm is:
<blockquote algorithm="convert a float value to an integral value">
To convert a floating point scalar value |X| to an [=integer scalar=] type |T|:
* If the original value of |X| is exactly representable in the target type |T|, then the result is that value.
* Otherwise, the result is the value in |T| that is closest to [=truncate=](|X|).

</blockquote>

Note: In other words, floating point to integer conversion rounds toward zero, then saturates in the target type.

<div class=note><span class=marker>Note:</span> For example:
* 3.9f converted to [=u32=] is 3u
* -1f converted to [=u32=] is 0u
* 1e20f converted to [=u32=] is the maximum u32 value, 4294967295u
* -3.9f converted to [=i32=] is -3i
* 1e20f converted to [=i32=] is the maximum i32 value, 2147483647i
* -1e20f converted to [=i32=] is the minimum i32 value, i32(-2147483648)

</div>

The <dfn noexport>numeric scalar conversion to floating point</dfn> algorithm is:
<blockquote>
When converting a [=numeric scalar=] value to a floating point type:
* If the original value is exactly representable in the destination type, then the result is that value.
    * Additionally, if the original value is zero and of [=integer scalar=] type, then the resulting value has a zero sign bit.
* Otherwise, the original value is not exactly representable.
    * If the original value is different from but lies between two adjacent finite values representable in the destination type,
         then the result is one of those two values.
         WGSL does not specify whether the larger or smaller representable
         value is chosen, and different instances of such a conversion may choose differently.
    * Otherwise, the original value lies outside the finite range of the destination type:
         * A [=shader-creation error=] results if the original expression is a [=const-expression=].
         * A [=pipeline-creation error=] results if the original expression is an [=override-expression=].
         * Otherwise the conversion proceeds as follows:
             1. Set |X| to the original value.
             2. If the source type is a floating point type with more mantissa bits than the destination type,
                 the extra mantissa bits of the source value *may* be discarded (i.e. treated as if they are 0).
                 Update |X| accordingly.
             3. If |X| is the most-positive or most-negative normal value of the destination type, then the result is |X|.
             4. Otherwise, the result is the infinity value of the destination type, with the same sign as |X|.
    * Otherwise, if the original value is a NaN for the source type, then the result is a NaN in the destination type.

</blockquote>

NOTE: An integer value may lie between two adjacent representable floating point values.
In particular, the [=f32=] type uses 23 explicit fractional bits.
Additionally, when the floating point value is in the normal range (the exponent is neither extreme value), then the mantissa is
the set of fractional bits together with an extra 1-bit at the most significant position at bit position 23.
Then, for example, integers 2<sup>28</sup> and 1+2<sup>28</sup> both map to the same floating point value: the difference in the
least significant 1 bit is not representable by the floating point format.
This kind of collision occurs for pairs of adjacent integers with a magnitude of at least 2<sup>25</sup>.

Note: The original value is always within range of the destination type when
the original type is one of [=i32=] or [=u32=] and the destination type is [=f32=].

Note: The original value is always within range of the destination type when
the source type is a floating point type with fewer exponent and mantissa bits than the target floating point type.

# Keyword and Token Summary # {#grammar}

## Keyword Summary ## {#keyword-summary}

* <dfn for=syntax_kw noexport>`alias`</dfn>
* <dfn for=syntax_kw noexport>`break`</dfn>
* <dfn for=syntax_kw noexport>`case`</dfn>
* <dfn for=syntax_kw noexport>`const`</dfn>
* <dfn for=syntax_kw noexport>`const_assert`</dfn>
* <dfn for=syntax_kw noexport>`continue`</dfn>
* <dfn for=syntax_kw noexport>`continuing`</dfn>
* <dfn for=syntax_kw noexport>`default`</dfn>
* <dfn for=syntax_kw noexport>`diagnostic`</dfn>
* <dfn for=syntax_kw noexport>`discard`</dfn>
* <dfn for=syntax_kw noexport>`else`</dfn>
* <dfn for=syntax_kw noexport>`enable`</dfn>
* <dfn for=syntax_kw noexport>`false`</dfn>
* <dfn for=syntax_kw noexport>`fn`</dfn>
* <dfn for=syntax_kw noexport>`for`</dfn>
* <dfn for=syntax_kw noexport>`if`</dfn>
* <dfn for=syntax_kw noexport>`let`</dfn>
* <dfn for=syntax_kw noexport>`loop`</dfn>
* <dfn for=syntax_kw noexport>`override`</dfn>
* <dfn for=syntax_kw noexport>`requires`</dfn>
* <dfn for=syntax_kw noexport>`return`</dfn>
* <dfn for=syntax_kw noexport>`struct`</dfn>
* <dfn for=syntax_kw noexport>`switch`</dfn>
* <dfn for=syntax_kw noexport>`true`</dfn>
* <dfn for=syntax_kw noexport>`var`</dfn>
* <dfn for=syntax_kw noexport>`while`</dfn>

## Reserved Words ## {#reserved-words}

A <dfn>reserved word</dfn> is a [=token=] which is reserved for future use.
A WGSL module [=shader-creation error|must not=] contain a reserved word.

The following are reserved words:

<pre class=include>
path: wgsl.reserved.bs.include
</pre>

## Syntactic Tokens ## {#syntactic-tokens}

A <dfn>syntactic token</dfn> is a sequence of special code points, used:
* to spell an expression operator, or
* as punctuation: to group, sequence, or separate other grammar elements.

The [=syntactic tokens=] are:

* <dfn for=syntax_sym lt='and' noexport>`'&'` (Code point: `U+0026`)</dfn>
* <dfn for=syntax_sym lt='and_and' noexport>`'&&'` (Code points: `U+0026` `U+0026`)</dfn>
* <dfn for=syntax_sym lt='arrow' noexport>`'->'` (Code points: `U+002D` `U+003E`)</dfn>
* <dfn for=syntax_sym lt='attr' noexport>`'@'` (Code point: `U+0040`)</dfn>
* <dfn for=syntax_sym lt='forward_slash' noexport>`'/'` (Code point: `U+002F`)</dfn>
* <dfn for=syntax_sym lt='bang' noexport>`'!'` (Code point: `U+0021`)</dfn>
* <dfn for=syntax_sym lt='bracket_left' noexport>`'['` (Code point: `U+005B`)</dfn>
* <dfn for=syntax_sym lt='bracket_right' noexport>`']'` (Code point: `U+005D`)</dfn>
* <dfn for=syntax_sym lt='brace_left' noexport>`'{'` (Code point: `U+007B`)</dfn>
* <dfn for=syntax_sym lt='brace_right' noexport>`'}'` (Code point: `U+007D`)</dfn>
* <dfn for=syntax_sym lt='colon' noexport>`':'` (Code point: `U+003A`)</dfn>
* <dfn for=syntax_sym lt='comma' noexport>`','` (Code point: `U+002C`)</dfn>
* <dfn for=syntax_sym lt='equal' noexport>`'='` (Code point: `U+003D`)</dfn>
* <dfn for=syntax_sym lt='equal_equal' noexport>`'=='` (Code points: `U+003D` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='not_equal' noexport>`'!='` (Code points: `U+0021` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='greater_than' noexport>`'>'` (Code point: `U+003E`)</dfn> (also <dfn for=syntax_sym lt='_greater_than' noexport>`_greater_than`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='greater_than_equal' noexport>`'>='` (Code points: `U+003E` `U+003D`)</dfn> (also <dfn for=syntax_sym lt='_greater_than_equal' noexport>`_greater_than_equal`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='shift_right' noexport>`'>>'` (Code point: `U+003E` `U+003E`)</dfn> (also <dfn for=syntax_sym lt='_shift_right' noexport>`_shift_right`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='less_than' noexport>`'<'` (Code point: `U+003C`)</dfn> (also <dfn for=syntax_sym lt='_less_than' noexport>`_less_than`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='less_than_equal' noexport>`'<='` (Code points: `U+003C` `U+003D`)</dfn> (also <dfn for=syntax_sym lt='_less_than_equal' noexport>`_less_than_equal`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='shift_left' noexport>`'<<'` (Code points: `U+003C` `U+003C`)</dfn> (also <dfn for=syntax_sym lt='_shift_left' noexport>`_shift_left`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='modulo' noexport>`'%'` (Code point: `U+0025`)</dfn>
* <dfn for=syntax_sym lt='minus' noexport>`'-'` (Code point: `U+002D`)</dfn>
* <dfn for=syntax_sym lt='minus_minus' noexport>`'--'` (Code points: `U+002D` `U+002D`)</dfn>
* <dfn for=syntax_sym lt='period' noexport>`'.'` (Code point: `U+002E`)</dfn>
* <dfn for=syntax_sym lt='plus' noexport>`'+'` (Code point: `U+002B`)</dfn>
* <dfn for=syntax_sym lt='plus_plus' noexport>`'++'` (Code points: `U+002B` `U+002B`)</dfn>
* <dfn for=syntax_sym lt='or' noexport>`'|'` (Code point: `U+007C`)</dfn>
* <dfn for=syntax_sym lt='or_or' noexport>`'||'` (Code points: `U+007C` `U+007C`)</dfn>
* <dfn for=syntax_sym lt='paren_left' noexport>`'('` (Code point: `U+0028`)</dfn>
* <dfn for=syntax_sym lt='paren_right' noexport>`')'` (Code point: `U+0029`)</dfn>
* <dfn for=syntax_sym lt='semicolon' noexport>`';'` (Code point: `U+003B`)</dfn>
* <dfn for=syntax_sym lt='star' noexport>`'*'` (Code point: `U+002A`)</dfn>
* <dfn for=syntax_sym lt='tilde' noexport>`'~'` (Code point: `U+007E`)</dfn>
* <dfn for=syntax_sym lt='underscore' noexport>`'_'` (Code point: `U+005F`)</dfn>
* <dfn for=syntax_sym lt='xor' noexport>`'^'` (Code point: `U+005E`)</dfn>
* <dfn for=syntax_sym lt='plus_equal' noexport>`'+='` (Code points: `U+002B` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='minus_equal' noexport>`'-='` (Code points: `U+002D` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='times_equal' noexport>`'*='` (Code points: `U+002A` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='division_equal' noexport>`'/='` (Code points: `U+002F` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='modulo_equal' noexport>`'%='` (Code points: `U+0025` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='and_equal' noexport>`'&='` (Code points: `U+0026` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='or_equal' noexport>`'|='` (Code points: `U+007C` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='xor_equal' noexport>`'^='` (Code points: `U+005E` `U+003D`)</dfn>
* <dfn for=syntax_sym lt='shift_right_assign' noexport>`'>>='` (Code point: `U+003E` `U+003E` `U+003D`)</dfn> (also <dfn for=syntax_sym lt='_shift_right_assign' noexport>`_shift_right_assign`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='shift_left_assign' noexport>`'<<='` (Code points: `U+003C` `U+003C` `U+003D`)</dfn> (also <dfn for=syntax_sym lt='_shift_left_assign' noexport>`_shift_left_assign`</dfn> for template disambiguation)
* <dfn for=syntax_sym lt='_template_args_end' noexport>`_template_args_end`</dfn>
    * Text:  `'>'` (Code point: `U+003E`)
    * This token is textually the same as the [=syntax_sym/greater_than=] syntactic token.
    * It is generated by template list disambiguation, and is used as the last token in a template list.
* <dfn for=syntax_sym lt='_template_args_start' noexport>`_template_args_start`</dfn>
    * Text: `'<'` (Code point: `U+003C`)
    * This token is textually the same as the [=syntax_sym/less_than=] syntactic token.
    * It is generated by template list disambiguation, and is used as the first token in a template list.
* <dfn for=syntax_sym lt='_disambiguate_template' noexport>`_disambiguate_template`</dfn>
    * Text: None
    * This token informs parser to scan for template lists.
    * It triggers template list disambiguation.

# Built-in Functions # {#builtin-functions}

Certain functions are [=predeclared=], provided by the implementation, and
therefore always available for use in a WGSL module.
These are called <dfn noexport>built-in functions</dfn>.

A built-in function is a family of functions, all with the same name,
but distinguished by the number, order, and types of their [=formal parameters=].
Each of these distinct function variations is an [=overload=].

Note: Each [=user-defined function=] only has one [=overload=].

Each [=overload=] is described below via:
* Type parameterizations, if any.
* The built-in function name, a parenthesized list of [=formal parameters=], and optionally a [=return type=].
* The behavior of this overload of the function.

When calling a built-in function, all arguments to the function are evaluated
before function evaluation begins.
See [[#function-calls]].

## Constructor Built-in Functions ## {#constructor-builtin-function}

A <dfn noexport>value constructor</dfn> built-in function explicitly creates a
value of a given type.

WGSL provides value constructors for all [=predeclared=] types and all
[=constructible=] [=structure=] types.
The constructor built-in functions have the same spelling as the types.
Wherever such a built-in function is used, the [=identifier=]
[=shader-creation error|must=] be [=in scope=] of the type and the [=identifier=]
[=shader-creation error|must not=] [=resolve=] to another declaration.

Note: The structure types returned by [[#frexp-builtin|frexp]],
[[#modf-builtin|modf]], and [[#atomic-rmw|atomicCompareExchangeWeak]] cannot be
written in WGSL modules.

Note: A value declaration of the type needs to be valid at that statement of
the WGSL text.

WGSL provides two kinds of value constructors:
* [[#zero-value-builtin-function|zero value constructors]]
* [[#value-constructor-builtin-function|value constructors]] (which also provide conversion)

### Zero Value Built-in Functions ### {#zero-value-builtin-function}

Each [=type/concrete=], [=constructible=] *T* has a unique <dfn noexport>zero value</dfn>,
and a corresponding built-in function written in WGSL as the type followed by an empty pair of parentheses: *T* `()`.
[=Abstract numeric types=] also have zero values, but there are no built-in functions to access them.

The zero values are as follows:

* `bool()` is `false`
* `i32()` is 0i
* `u32()` is 0u
* `f32()` is 0.0f
* `f16()` is 0.0h
* The zero value for an *N*-component vector of type *T* is the *N*-component vector of the zero value for *T*.
* The zero value for an *C*-column *R*-row matrix of type *T* is the matrix of those dimensions filled with the zero value for *T*.
* The zero value for a [=constructible=] *N*-element array with element type *E* is an array of *N* elements of the zero value for *E*.
* The zero value for a [=constructible=] structure type *S* is the structure value *S* with zero-valued members.
* The zero value of an [=AbstractInt=] is 0.
* The zero value of an [=AbstractFloat=] is 0.0.

Note: WGSL does not have zero built-in functions for [=atomic types=],
[=runtime-sized=] arrays, or other types that are not [=constructible=].

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn T() -> T</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=constructible=] type.<br>
  <tr><td>Description
      <td>Construct [=zero value=] of the type `T`.
</table>

Note: Zero-filled vectors of AbstractInt can be written as
`vec2()`, `vec3()`, and `vec4()`.

<div class='example' heading="Zero-valued vectors">
  <xmp highlight=wgsl>
    vec2<f32>()                 // The zero-valued vector of two f32 components.
    vec2<f32>(0.0, 0.0)         // The same value, written explicitly.

    vec3<i32>()                 // The zero-valued vector of three i32 components.
    vec3<i32>(0, 0, 0)          // The same value, written explicitly.
  </xmp>
</div>

<div class='example' heading="Zero-valued arrays">
  <xmp highlight=wgsl>
    array<bool, 2>()               // The zero-valued array of two booleans.
    array<bool, 2>(false, false)   // The same value, written explicitly.
  </xmp>
</div>

<div class='example wgsl global-scope' heading="Zero-valued structures">
  <xmp highlight=wgsl>
    struct Student {
      grade: i32,
      GPA: f32,
      attendance: array<bool,4>
    }

    fn func() {
      var s: Student;

      // The zero value for Student
      s = Student();

      // The same value, written explicitly.
      s = Student(0, 0.0, array<bool,4>(false, false, false, false));

      // The same value, written with zero-valued members.
      s = Student(i32(), f32(), array<bool,4>());
    }
  </xmp>
</div>

### Value Constructor Built-in Functions ### {#value-constructor-builtin-function}

The built-in functions defined in following subsections create a [=constructible=] value by:
* Copying an existing value of the same type (i.e. the identity function), or
* Creating a composite value from an explicit list of components.
* Converting from another value type.

The vector and matrix forms construct vector and matrix values from various combinations of components and subvectors
with matching component types.
There are [=overloads=] for constructing vectors and matrices that specify the dimensions of the target type without having to
specify the component type; the component type is inferred from the constructor arguments.

#### `array` #### {#array-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn array<T, N>(e1 : T, ..., eN : T) -> array<T, N>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=type/concrete=] and [=constructible=]
  <tr><td>Description
      <td>Construction of an [=array=] from elements.

      Note: array&lt;|T|,|N|&gt; is [=constructible=] because its [=element count=]
      is equal to the number of arguments to the constructor, and hence
      fully determined at [=shader module creation|shader-creation=] time.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn array(e1 : T, ..., eN : T) -> array<T, N>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=constructible=]
  <tr><td>Description
      <td>Construction of an [=array=] from elements.

      The component type is inferred from the elements' type.
      The size of the array is determined by the number of elements.
</table>

#### `bool` #### {#bool-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bool(e : T) -> bool</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=scalar=] type.
  <tr><td>Description
      <td>Construct a [=bool=] value.

      If `T` is [=bool=], this is an identity operation.<br>
      Otherwise this is a boolean coercion.
      The result is `false` if `e` is a [=zero value=] (or -0.0 for floating point types) and `true` otherwise.
</table>

#### `f16` #### {#f16-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn f16(e : T) -> f16</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=scalar=] type
  <tr><td>Description
      <td>Construct an [=f16=] value.

      If `T` is [=f16=], this is an identity operation.<br>
      If `T` is a [=numeric scalar=] (other than [=f16=]), `e` is converted to [=f16=] (including invalid conversions).<br>
      If `T` is [=bool=], the result is `1.0h` if `e` is `true` and `0.0h` otherwise.
</table>

#### `f32` #### {#f32-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn f32(e : T) -> f32</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=] type
  <tr><td>Description
      <td>Construct an [=f32=] value.

      If `T` is [=f32=], this is an identity operation.<br>
      If `T` is a [=numeric scalar=] (other than [=f32=]), `e` is converted to [=f32=] (including invalid conversions).<br>
      If `T` is [=bool=], the result is `1.0f` if `e` is `true` and `0.0f` otherwise.
</table>

#### `i32` #### {#i32-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn i32(e : T) -> i32</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=scalar=] type
  <tr><td>Description
      <td>Construct an [=i32=] value.

      If `T` is [=i32=], this is an identity operation.<br>
      If `T` is [=u32=], this is a reinterpretation of bits (i.e. the result is the unique value in [=i32=] that has the same bit pattern as `e`).<br>
      If `T` is a [[#floating-point-types|floating point type]], `e` is [=scalar floating point to integral conversion|converted=] to [=i32=], rounding towards zero.<br>
      If `T` is [=bool=], the result is `1i` if `e` is `true` and `0i` otherwise.<br>
      If `T` is an [=AbstractInt=], this is an identity operation if `e` can be represented in [=i32=], otherwise it produces a [=shader-creation error=].
</table>

#### `mat2x2` #### {#mat2x2-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x2<T>(e : mat2x2<S>) -> mat2x2<T>
          @const @must_use fn mat2x2(e : mat2x2<S>) -> mat2x2<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 2x2 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x2<T>(v1 : vec2<T>, v2 : vec2<T>) -> mat2x2<T>
          @const @must_use fn mat2x2(v1 : vec2<T>, v2 : vec2<T>) -> mat2x2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 2x2 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x2<T>(e1 : T, e2 : T, e3 : T, e4 : T) -> mat2x2<T>
          @const @must_use fn mat2x2(e1 : T, e2 : T, e3 : T, e4 : T) -> mat2x2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 2x2 column-major [=matrix=] from elements.

          Same as mat2x2(vec2(e1,e2), vec2(e3,e4)).
</table>

#### `mat2x3` #### {#mat2x3-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x3<T>(e : mat2x3<S>) -> mat2x3<T>
          @const @must_use fn mat2x3(e : mat2x3<S>) -> mat2x3<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 2x3 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x3<T>(v1 : vec3<T>, v2 : vec3<T>) -> mat2x3<T>
          @const @must_use fn mat2x3(v1 : vec3<T>, v2 : vec3<T>) -> mat2x3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 2x3 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x3<T>(e1 : T, ..., e6 : T) -> mat2x3<T>
          @const @must_use fn mat2x3(e1 : T, ..., e6 : T) -> mat2x3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 2x3 column-major [=matrix=] from elements.

          Same as mat2x3(vec3(e1,e2,e3), vec3(e4,e5,e6)).
</table>

#### `mat2x4` #### {#mat2x4-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x4<T>(e : mat2x4<S>) -> mat2x4<T>
          @const @must_use fn mat2x4(e : mat2x4<S>) -> mat2x4<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 2x4 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x4<T>(v1 : vec4<T>, v2 : vec4<T>) -> mat2x4<T>
          @const @must_use fn mat2x4(v1 : vec4<T>, v2 : vec4<T>) -> mat2x4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 2x4 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat2x4<T>(e1 : T, ..., e8 : T) -> mat2x4<T>
          @const @must_use fn mat2x4(e1 : T, ..., e8 : T) -> mat2x4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 2x4 column-major [=matrix=] from elements.

          Same as mat2x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8)).
</table>

#### `mat3x2` #### {#mat3x2-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x2<T>(e : mat3x2<S>) -> mat3x2<T>
          @const @must_use fn mat3x2(e : mat3x2<S>) -> mat3x2<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 3x2 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x2<T>(v1 : vec2<T>,
                                        v2 : vec2<T>,
                                        v3 : vec2<T>) -> mat3x2<T>
          @const @must_use fn mat3x2(v1 : vec2<T>,
                                     v2 : vec2<T>,
                                     v3 : vec2<T>) -> mat3x2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 3x2 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x2<T>(e1 : T, ..., e6 : T) -> mat3x2<T>
          @const @must_use fn mat3x2(e1 : T, ..., e6 : T) -> mat3x2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 3x2 column-major [=matrix=] from elements.

          Same as mat3x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6)).
</table>

#### `mat3x3` #### {#mat3x3-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x3<T>(e : mat3x3<S>) -> mat3x3<T>
          @const @must_use fn mat3x3(e : mat3x3<S>) -> mat3x3<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 3x3 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x3<T>(v1 : vec3<T>,
                                        v2 : vec3<T>,
                                        v3 : vec3<T>) -> mat3x3<T>
          @const @must_use fn mat3x3(v1 : vec3<T>,
                                     v2 : vec3<T>,
                                     v3 : vec3<T>) -> mat3x3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 3x3 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x3<T>(e1 : T, ..., e9 : T) -> mat3x3<T>
          @const @must_use fn mat3x3(e1 : T, ..., e9 : T) -> mat3x3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 3x3 column-major [=matrix=] from elements.

          Same as mat3x3(vec3(e1,e2,e3), vec3(e4,e4,e6), vec3(e7,e8,e9)).
</table>

#### `mat3x4` #### {#mat3x4-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x4<T>(e : mat3x4<S>) -> mat3x4<T>
          @const @must_use fn mat3x4(e : mat3x4<S>) -> mat3x4<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 3x4 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x4<T>(v1 : vec4<T>,
                                        v2 : vec4<T>,
                                        v3 : vec4<T>) -> mat3x4<T>
          @const @must_use fn mat3x4(v1 : vec4<T>,
                                     v2 : vec4<T>,
                                     v3 : vec4<T>) -> mat3x4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 3x4 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat3x4<T>(e1 : T, ..., e12 : T) -> mat3x4<T>
          @const @must_use fn mat3x4(e1 : T, ..., e12 : T) -> mat3x4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 3x4 column-major [=matrix=] from elements.

          Same as mat3x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12)).
</table>

#### `mat4x2` #### {#mat4x2-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x2<T>(e : mat4x2<S>) -> mat4x2<T>
          @const @must_use fn mat4x2(e : mat4x2<S>) -> mat4x2<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 4x2 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x2<T>(v1 : vec2<T>,
                                        v2 : vec2<T>,
                                        v3 : vec2<T>,
                                        v4: vec2<T>) -> mat4x2<T>
          @const @must_use fn mat4x2(v1 : vec2<T>,
                                     v2 : vec2<T>,
                                     v3 : vec2<T>,
                                     v4: vec2<T>) -> mat4x2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 4x2 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x2<T>(e1 : T, ..., e8 : T) -> mat4x2<T>
          @const @must_use fn mat4x2(e1 : T, ..., e8 : T) -> mat4x2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 4x2 column-major [=matrix=] from elements.

          Same as mat4x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6), vec2(e7,e8)).
</table>

#### `mat4x3` #### {#mat4x3-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x3<T>(e : mat4x3<S>) -> mat4x3<T>
          @const @must_use fn mat4x3(e : mat4x3<S>) -> mat4x3<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 4x3 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x3<T>(v1 : vec3<T>,
                                        v2 : vec3<T>,
                                        v3 : vec3<T>,
                                        v4 : vec3<T>) -> mat4x3<T>
          @const @must_use fn mat4x3(v1 : vec3<T>,
                                     v2 : vec3<T>,
                                     v3 : vec3<T>,
                                     v4 : vec3<T>) -> mat4x3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 4x3 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x3<T>(e1 : T, ..., e12 : T) -> mat4x3<T>
          @const @must_use fn mat4x3(e1 : T, ..., e12 : T) -> mat4x3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 4x3 column-major [=matrix=] from elements.

          Same as mat4x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9), vec3(e10,e11,e12)).
</table>

#### `mat4x4` #### {#mat4x4-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x4<T>(e : mat4x4<S>) -> mat4x4<T>
          @const @must_use fn mat4x4(e : mat4x4<S>) -> mat4x4<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=f16=] or [=f32=]<br>
      `S` is [FLOATSCALAR]
  <tr><td>Description
      <td>Constructor for a 4x4 column-major [=matrix=].

      If `T` does not match `S`, a [[#floating-point-conversion|conversion]] occurs.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x4<T>(v1 : vec4<T>,
                                        v2 : vec4<T>,
                                        v3 : vec4<T>,
                                        v4 : vec4<T>) -> mat4x4<T>
          @const @must_use fn mat4x4(v1 : vec4<T>,
                                     v2 : vec4<T>,
                                     v3 : vec4<T>,
                                     v4 : vec4<T>) -> mat4x4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 4x4 column-major [=matrix=] from column vectors.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn mat4x4<T>(e1 : T, ..., e16 : T) -> mat4x4<T>
          @const @must_use fn mat4x4(e1 : T, ..., e16 : T) -> mat4x4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [FLOATSCALAR]
  <tr><td>Description
      <td>Construct a 4x4 column-major [=matrix=] from elements.

          Same as mat4x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12), vec4(e13,e14,e15,e16)).
</table>

#### Structures #### {#structures-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn S(e1 : T1, ..., eN : TN) -> S</xmp>
  <tr><td>Parameterization
      <td>`S` is a [=constructible=] structure type with members having types `T1` ... `TN`.
  <tr><td>Description
      <td>Construct a [=structure=] of type `S` from members.
</table>

#### `u32` #### {#u32-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn u32(e : T) -> u32</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=scalar=] type
  <tr><td>Description
      <td>Construct a [=u32=] value.

      If `T` is [=u32=], this is an identity operation.<br>
      If `T` is [=i32=], this is a reinterpretation of bits (i.e. the result is the unique value in [=u32=] that has the same bit pattern as `e`).<br>
      If `T` is a [[#floating-point-types|floating point type]], `e` is [=scalar floating point to integral conversion|converted=] to [=u32=], rounding towards zero.<br>
      If `T` is [=bool=], the result is `1u` if `e` is `true` and `0u` otherwise.<br>
      If `T` is [=AbstractInt=], this is an identity operation if the `e` can be represented in [=u32=], otherwise it produces a [=shader-creation error=].
  <tr><td>
      <td>

      Note: The overload from [=AbstractInt=] exists so expressions such as `u32(4*1000*1000*1000)` can create a u32 value that would otherwise overflow the i32 type. If this overload did not exist, [=overload resolution=] would select the `u32(i32)` overload, the AbstractInt expression would automatically convert to i32, and this would cause a shader-creation error due to overflow.
</table>

#### `vec2` #### {#vec2-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec2<T>(e : T) -> vec2<T>
          @const @must_use fn vec2(e : S) -> vec2<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=]<br>
      `S` is [=scalar=]
  <tr><td>Description
      <td>Construction of a two-component [=vector=] with `e` as both components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec2<T>(e : vec2<S>) -> vec2<T>
          @const @must_use fn vec2(e : vec2<S>) -> vec2<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=]<br>
      `S` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a two-component [=vector=] with `e.x` and `e.y` as components.

      If `T` does not match `S` a conversion is used and the components are `T(e.x)` and `T(e.y)`.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec2<T>(e1 : T, e2 : T) -> vec2<T>
          @const @must_use fn vec2(e1 : T, e2 : T) -> vec2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a two-component [=vector=] with `e1` and `e2` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec2() -> vec2<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is AbstractInt
  <tr><td>Description
      <td>Returns the value `vec2(0,0)`.
</table>

#### `vec3` #### {#vec3-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec3<T>(e : T) -> vec3<T>
          @const @must_use fn vec3(e : S) -> vec3<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=]<br>
      `S` is [=scalar=]
  <tr><td>Description
      <td>Construction of a three-component [=vector=] with `e` as all components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec3<T>(e : vec3<S>) -> vec3<T>
          @const @must_use fn vec3(e : vec3<S>) -> vec3<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=]<br>
      `S` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a three-component [=vector=] with `e.x`, `e.y`, and `e.z` as components.

      If `T` does not match `S` a conversion is used and the components are `T(e.x)`, `T(e.y)`, and  `T(e.z)`.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec3<T>(e1 : T, e2 : T, e3 : T) -> vec3<T>
          @const @must_use fn vec3(e1 : T, e2 : T, e3 : T) -> vec3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a three-component [=vector=] with `e1`, `e2`, and `e3` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec3<T>(v1 : vec2<T>, e1 : T) -> vec3<T>
          @const @must_use fn vec3(v1 : vec2<T>, e1 : T) -> vec3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a three-component [=vector=] with `v1.x`, `v1.y`, and `e1` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec3<T>(e1 : T, v1 : vec2<T>) -> vec3<T>
          @const @must_use fn vec3(e1 : T, v1 : vec2<T>) -> vec3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a three-component [=vector=] with `e1`, `v1.x`, and `v1.y` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec3() -> vec3<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is AbstractInt
  <tr><td>Description
      <td>Returns the value `vec3(0,0,0)`.
</table>

#### `vec4` #### {#vec4-builtin}

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(e : T) -> vec4<T>
          @const @must_use fn vec4(e : S) -> vec4<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=]<br>
      `S` is [=scalar=]
  <tr><td>Description
      <td>Construction of a four-component [=vector=] with `e` as all components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(e : vec4<S>) -> vec4<T>
          @const @must_use fn vec4(e : vec4<S>) -> vec4<S>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=scalar=]<br>
      `S` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `e.x`, `e.y`, `e.z`, and `e.w` as components.

      If `T` does not match `S` a conversion is used and the components are `T(e.x)`, `T(e.y)`, `T(e.z)` and  `T(e.w)`.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(e1 : T, e2 : T, e3 : T, e4 : T) -> vec4<T>
          @const @must_use fn vec4(e1 : T, e2 : T, e3 : T, e4 : T) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `e1`, `e2`, `e3`, and `e4` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(e1 : T, v1 : vec2<T>, e2 : T) -> vec4<T>
          @const @must_use fn vec4(e1 : T, v1 : vec2<T>, e2 : T) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `e1`, `v1.x`, `v1.y`, and `e2` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(e1 : T, e2 : T, v1 : vec2<T>) -> vec4<T>
          @const @must_use fn vec4(e1 : T, e2 : T, v1 : vec2<T>) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `e1`, `e2`, `v1.x`, and `v1.y` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(v1 : vec2<T>, v2 : vec2<T>) -> vec4<T>
          @const @must_use fn vec4(v1 : vec2<T>, v2 : vec2<T>) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `v1.x`, `v1.y`, `v2.x`, and `v2.y` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(v1 : vec2<T>, e1 : T, e2 : T) -> vec4<T>
          @const @must_use fn vec4(v1 : vec2<T>, e1 : T, e2 : T) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `v1.x`, `v1.y`, `e1`, and `e2` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(v1 : vec3<T>, e1 : T) -> vec4<T>
          @const @must_use fn vec4(v1 : vec3<T>, e1 : T) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `v1.x`, `v1.y`, `v1.z`, and `e1` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4<T>(e1 : T, v1 : vec3<T>) -> vec4<T>
          @const @must_use fn vec4(e1 : T, v1 : vec3<T>) -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is [=scalar=]
  <tr><td>Description
      <td>[=Component-wise=] construction of a four-component [=vector=] with `e1`, `v1.x`, `v1.y`, and `v1.z` as components.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>
          @const @must_use fn vec4() -> vec4<T>
        </xmp>
  <tr><td>Parameterization
      <td>`T` is AbstractInt
  <tr><td>Description
      <td>Returns the value `vec4(0,0,0,0)`.
</table>

## Bit Reinterpretation Built-in Functions ## {#bit-reinterp-builtin-functions}

### `bitcast` ### {#bitcast-builtin}

A `bitcast` built-in function is used to reinterpret the bit representation of
a value in one type as a value in another type.

The internal layout rules are described in [[#internal-value-layout]].

<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<T>(e : T) -> T</xmp>
  <tr><td>Parameterization
      <td>`T` is a [=type/concrete=] [=numeric scalar=] or [=type/concrete=] [=numeric vector=]
  <tr><td>Description
      <td>Identity transform.<br>
      [=Component-wise=] when `T` is a [=vector=].<br>
      The result is `e`.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<T>(e : S) -> T</xmp>
  <tr><td>Parameterization
      <td>`S` is i32, u32, or f32<br>
      `T` is not `S` and is i32, u32, or f32
  <tr><td>Description
      <td>Reinterpretation of bits as `T`.<br>
      The result is the reintepretation of bits in `e` as a `T` value.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<vecN<T>>(e : vecN<S>) -> vecN<T></xmp>
  <tr><td>Parameterization
      <td>`S` is i32, u32, or f32<br>
      `T` is not `S` and is i32, u32, or f32
  <tr><td>Description
      <td>[=Component-wise=] reinterpretation of bits as `T`.<br>
      The result is the reintepretation of bits in `e` as a `vecN<T>` value.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<u32>(e : AbstractInt) -> u32

                            @const @must_use fn bitcast<vecN<u32>>(e : vecN<AbstractInt>) -> vecN<u32></xmp>
  <tr><td>Parameterization
      <td>
  <tr><td>Description
      <td>The identity operation if `e` can be represented as [=u32=],
      otherwise it produces a [=shader-creation error=].
      That is, produces the same result as `u32(e)`.

      [=Component-wise=] when `e` is a vector.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<T>(e : vec2<f16>) -> T</xmp>
  <tr><td>Parameterization
      <td>`T` is i32, u32, or f32
  <tr><td>Description
      <td>[=Component-wise=] reinterpretation of bits as `T`.<br>
      The result is the reintepretation of the 32 bits in `e` as a `T` value, following the internal layout rules.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<vec2<T>>(e : vec4<f16>) -> vec2<T></xmp>
  <tr><td>Parameterization
      <td>`T` is i32, u32, or f32<br>
  <tr><td>Description
      <td>[=Component-wise=] reinterpretation of bits as `T`.<br>
      The result is the reintepretation of the 64 bits in `e` as a `T` value, following the internal layout rules.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<vec2<f16>>(e : T) -> vec2<f16></xmp>
  <tr><td>Parameterization
      <td>`T` is i32, u32, or f32
  <tr><td>Description
      <td>[=Component-wise=] reinterpretation of bits as f16.<br>
      The result is the reintepretation of the 32 bits in `e` as an f16 value, following the internal layout rules.
</table>
<table class='data builtin'>
  <tr><td style="width:10%">Overload
      <td>
        <xmp highlight=wgsl>@const @must_use fn bitcast<vec4<f16>>(e : vec2<T>) -> vec4<f16></xmp>
  <tr><td>Parameterization
      <td>`T` is i32, u32, or f32
  <tr><td>Description
      <td>[=Component-wise=] reinterpretation of bits as `vec2<f16>`.<br>
      The result is the reintepretation of the 64 bits in `e` as an f16 value, following the internal layout rules.
</table>

## Logical Built-in Functions ## {#logical-builtin-functions}

### `all` ### {#all-builtin}
<table class='data builtin'>
  <tr algorithm="vector all">
    <td style="width:10%">Overload
    <td>
      <xmp highlight=wgsl>@const @must_use fn all(e: vecN<bool>) -> bool</xmp>
  <tr>
    <td>Description
    <td>Returns true if each component of `e` is true.
</table>

<table class='data builtin'>
  <tr algorithm="scalar all">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>@const @must_use fn all(e: bool) -> bool</xmp>
  <tr>
    <td>Description
    <td>Returns `e`.
</table>

### `any` ### {#any-builtin}
<table class='data builtin'>
  <tr algorithm="vector any">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn any(e: vecN<bool>) -> bool
      </xmp>
  <tr>
    <td style="width:10%">Description
    <td>Returns true if any component of `e` is true.
</table>

<table class='data builtin'>
  <tr algorithm="scalar any">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>@const @must_use fn any(e: bool) -> bool</xmp>
  <tr>
    <td>Description
    <td>Returns `e`.
</table>

### `select` ### {#select-builtin}
<table class='data builtin'>
  <tr algorithm="scalar select">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn select(f: T,
                                   t: T,
                                   cond: bool) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [=scalar=] or [=vector=]
  <tr>
    <td>Description
    <td>Returns `t` when `cond` is true, and `f` otherwise.
</table>

<table class='data builtin'>
  <tr algorithm="vector select">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn select(f: vecN<T>,
                                   t: vecN<T>,
                                   cond: vecN<bool>) -> vecN<T>
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [=scalar=]
  <tr>
    <td>Description
    <td>[=Component-wise=] selection. Result component `i` is evaluated
        as `select(f[i], t[i], cond[i])`.
</table>

## Array Built-in Functions ## {#array-builtin-functions}

### `arrayLength` ### {#arrayLength-builtin}
<table class='data builtin'>
  <tr algorithm="runtime-sized array length">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn arrayLength(p: ptr<storage, array<E>, AM>) -> u32
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`E` is an element type for a [=runtime-sized=] array,<br>
        [=access mode=] `AM` is [=access/read=] or [=access/read_write=]
  <tr>
    <td>Description
    <td>Returns [=NRuntime=], the number of elements in the [=runtime-sized=] array.

        See [[#buffer-binding-determines-runtime-sized-array-element-count]]
</table>

<div class='example wgsl global-scope' heading='Getting the number of elements in a runtime-sized array'>
  <xmp highlight=wgsl>
struct PointLight {
  position : vec3f,
  color : vec3f,
}

struct LightStorage {
  pointCount : u32,
  point : array<PointLight>,
}

@group(0) @binding(1) var<storage> lights : LightStorage;

fn num_point_lights() -> u32 {
  return arrayLength( &lights.point );
}
  </xmp>
</div>

## Numeric Built-in Functions ## {#numeric-builtin-functions}

### `abs` ### {#abs-float-builtin}
<table class='data builtin'>
  <tr algorithm="float abs">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn abs(e: T ) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLNUMERICDECL]
  <tr>
    <td>Description
    <td>The absolute value of `e`.
    [=Component-wise=] when `T` is a vector.

    If `e` is a floating-point type, then the result is `e` with a positive sign bit.
    If `e` is an unsigned [=integer scalar=] type, then the result is `e`.
    If `e` is a signed [=integer scalar=] type and evaluates to the largest
    negative value, then the result is `e`.
</table>

### `acos` ### {#acos-builtin}
<table class='data builtin'>
  <tr algorithm="acos">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn acos(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the principal value, in radians, of the inverse cosine (cos<sup>-1</sup>) of `e`.<br>
    That is, approximates `x` with 0 &le; `x` &le; &pi;, such that `cos`(`x`) = `e`.

    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful when `abs(e)` &gt; 1.
</table>

### `acosh` ### {#acosh-builtin}
<table class='data builtin'>
  <tr algorithm="acosh">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn acosh(x: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the inverse hyperbolic cosine (cosh<sup>-1</sup>) of `x`, as a [=hyperbolic angle=].<br>
    That is, approximates `a` with 0 &le; a &le; &infin;, such that `cosh`(`a`) = `x`.

    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful when `x` &lt; 1.

</table>

### `asin` ### {#asin-builtin}
<table class='data builtin'>
  <tr algorithm="asin">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn asin(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the principal value, in radians, of the inverse sine (sin<sup>-1</sup>) of `e`.<br>
    That is, approximates `x` with -&pi;/2 &le; `x` &le; &pi;/2, such that `sin`(`x`) = `e`.

    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful when `abs(e)` &gt; 1.
</table>

### `asinh` ### {#asinh-builtin}
<table class='data builtin'>
  <tr algorithm="asinh">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn asinh(y: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the inverse hyperbolic sine (sinh<sup>-1</sup>) of `y`, as a [=hyperbolic angle=].<br>
    That is, approximates `a` such that `sinh`(`y`) = `a`.

    [=Component-wise=] when `T` is a vector.
</table>

### `atan` ### {#atan-builtin}
<table class='data builtin'>
  <tr algorithm="atan">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn atan(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the principal value, in radians, of the inverse tangent (tan<sup>-1</sup>) of `e`.<br>
    That is, approximates `x` with &minus; &pi;/2 &le; `x` &le; &pi;/2, such that `tan`(`x`) = `e`.

    [=Component-wise=] when `T` is a vector.
</table>

### `atanh` ### {#atanh-builtin}
<table class='data builtin'>
  <tr algorithm="atanh">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn atanh(t: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the inverse hyperbolic tangent (tanh<sup>-1</sup>) of `t`, as a [=hyperbolic angle=].<br>
    That is, approximates `a` such that `tanh`(`a`) = `t`.

    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful when `abs(t)` &ge; 1.

</table>

### `atan2` ### {#atan2-builtin}
<table class='data builtin'>
  <tr algorithm="atan2">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn atan2(y: T,
                                  x: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns an [=angle=], in radians, in the interval [-&pi;, &pi;] whose tangent is `y`&divide;`x`.

    The quadrant selected by the result depends on the signs of `y` and `x`.
    For example, the function may be implemented as:

    * `atan(y/x)` when `x` &gt; 0
    * `atan(y/x)` + &pi; when (`x` &lt; 0) and (`y` &gt; 0)
    * `atan(y/x)` - &pi; when (`x` &lt; 0) and (`y` &lt; 0)

    <div class=note>
    <span class=marker>Note:</span> The error in the result is unbounded:
    * When `abs(x)` is very small, e.g. subnormal for its type,
    * At the origin (`x`,`y`) = (0,0), or
    * When `y` is subnormal or infinite.

    </div>

    [=Component-wise=] when `T` is a vector.
</table>

### `ceil` ### {#ceil-builtin}
<table class='data builtin'>
  <tr algorithm="ceil">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn ceil(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the [=ceiling expression|ceiling=] of `e`.
    [=Component-wise=] when `T` is a vector.
</table>

### `clamp` ### {#clamp}
<table class='data builtin'>
  <tr algorithm="clamp">
  <td style="width:10%">Overload
  <td class="nowrap">
    <xmp highlight=wgsl>
      @const @must_use fn clamp(e: T,
                                low: T,
                                high: T) -> T
    </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLNUMERICDECL]
  <tr>
    <td>Description
    <td>Restricts the value of `e` within a range.

    If `T` is an integer type, then the result is `min(max(e, low), high)`.

    If `T` is a floating-point type, then the result is either `min(max(e,
    low), high)`, or the median of the three values `e`, `low`, `high`.

    [=Component-wise=] when `T` is a vector.

    If `low` is greater than `high`, then:
    * It is a [=shader-creation error=] if `low` and `high` are [=const-expressions=].
    * It is a [=pipeline-creation error=] if `low` and `high` are [=override-expressions=].
</table>

### `cos` ### {#cos-builtin}
<table class='data builtin'>
  <tr algorithm="cos">
  <td style="width:10%">Overload
  <td class="nowrap">
    <xmp highlight=wgsl>@const @must_use fn cos(e: T) -> T</xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the cosine of `e`, where `e` is in radians.
    [=Component-wise=] when `T` is a vector.
</table>

### `cosh` ### {#cosh-builtin}
<table class='data builtin'>
  <tr algorithm="cosh">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn cosh(a: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the hyperbolic cosine of `a`, where `a` is a [=hyperbolic angle=].
    Approximates the pure mathematical function (*e*<sup>a</sup> + *e*<sup>&minus;a</sup>)&divide;2,
    but not necessarily computed that way.

    [=Component-wise=] when `T` is a vector
</table>

### `countLeadingZeros` ### {#countLeadingZeros-builtin}
<table class='data builtin'>
  <tr algorithm="count leading zeroes">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn countLeadingZeros(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [INTEGRAL]
  <tr>
    <td>Description
    <td>The number of consecutive 0 bits starting from the most significant bit
        of `e`, when `T` is a scalar type.<br>
        [=Component-wise=] when `T` is a vector.<br>
        Also known as "clz" in some languages.
</table>

### `countOneBits` ### {#countOneBits-builtin}
<table class='data builtin'>
  <tr algorithm="count 1 bits">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn countOneBits(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [INTEGRAL]
  <tr>
    <td>Description
    <td>The number of 1 bits in the representation of `e`.<br>
        Also known as "population count".<br>
        [=Component-wise=] when `T` is a vector.
</table>

### `countTrailingZeros` ### {#countTrailingZeros-builtin}
<table class='data builtin'>
  <tr algorithm="count trailing zeroes">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn countTrailingZeros(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [INTEGRAL]
  <tr>
    <td>Description
    <td>The number of consecutive 0 bits starting from the least significant bit
        of `e`, when `T` is a scalar type.<br>
        [=Component-wise=] when `T` is a vector.<br>
        Also known as "ctz" in some languages.
</table>

### `cross` ### {#cross-builtin}
<table class='data builtin'>
  <tr algorithm="vector case, cross">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn cross(e1: vec3<T>,
                                  e2: vec3<T>) -> vec3<T>
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat, f32, or f16
  <tr>
    <td>Description
    <td>Returns the cross product of `e1` and `e2`.
</table>

### `degrees` ### {#degrees-builtin}
<table class='data builtin'>
  <tr algorithm="degrees">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn degrees(e1: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Converts radians to degrees, approximating `e1`&nbsp;&times;&nbsp;180&nbsp;&div;&nbsp;&pi;.
    [=Component-wise=] when `T` is a vector
</table>

### `determinant` ### {#determinant-builtin}
<table class='data builtin'>
  <tr algorithm="determinant">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn determinant(e: matCxC<T>) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat, f32, or f16
  <tr>
    <td>Description
    <td>Returns the determinant of `e`.
</table>

### `distance` ### {#distance-builtin}
<table class='data builtin'>
  <tr algorithm="distance">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn distance(e1: T,
                                     e2: T) -> S
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the distance between `e1` and `e2` (e.g. `length(e1 - e2)`).
</table>

### `dot` ### {#dot-builtin}
<table class='data builtin'>
  <tr algorithm="dot">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn dot(e1: vecN<T>,
                                e2: vecN<T>) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractInt, AbstractFloat, i32, u32, f32, or f16
  <tr>
    <td>Description
    <td>Returns the dot product of `e1` and `e2`.
</table>

### `dot4U8Packed` ### {#dot4U8Packed-builtin}
<table class='data builtin'>
  <tr algorithm="dot4U8Packed">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn dot4U8Packed(e1: u32,
                                         e2: u32) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>`e1` and `e2` are interpreted as vectors with four 8-bit unsigned integer components.
        Return the unsigned integer dot product of these two vectors.
</table>

### `dot4I8Packed` ### {#dot4I8Packed-builtin}
<table class='data builtin'>
  <tr algorithm="dot4I8Packed">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn dot4I8Packed(e1: u32,
                                         e2: u32) -> i32
      </xmp>
  <tr>
    <td>Description
    <td>`e1` and `e2` are interpreted as vectors with four 8-bit signed integer components.
        Return the signed integer dot product of these two vectors. Each component is sign-extended
        to i32 before performing the multiply, and then the add operations are done in WGSL i32 with
        wrapping behaviour.
</table>

### `exp` ### {#exp-builtin}
<table class='data builtin'>
  <tr algorithm="exp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn exp(e1: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the natural exponentiation of `e1` (e.g. `e`<sup>`e1`</sup>).
    [=Component-wise=] when `T` is a vector.
</table>

### `exp2` ### {#exp2-builtin}
<table class='data builtin'>
  <tr algorithm="exp2">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn exp2(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns 2 raised to the power `e` (e.g. `2`<sup>`e`</sup>).
    [=Component-wise=] when `T` is a vector.
</table>

### `extractBits` (signed) ### {#extractBits-signed-builtin}
<table class='data builtin'>
  <tr algorithm="signed extract bits">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn extractBits(e: T,
                                        offset: u32,
                                        count: u32) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [SIGNEDINTEGRAL]
  <tr>
    <td>Description
    <td>Reads bits from an integer, with sign extension.

    When `T` is a scalar type, then:
    <ul>
    <li>`w` is the bit width of `T`
    <li>`o = min(offset, w)`
    <li>`c = min(count, w - o)`
    <li>The result is 0 if `c` is 0.
    <li>Otherwise, bits `0..c - 1` of the result are copied from bits
       `o..o + c - 1` of `e`.
       Other bits of the result are the same as bit `c - 1` of the result.
    </ul>
    [=Component-wise=] when `T` is a vector.

    If `count` + `offset` is greater than `w`, then:
    * It is a [=shader-creation error=] if `count` and `offset` are [=const-expressions=].
    * It is a [=pipeline-creation error=] if `count` and `offset` are [=override-expressions=].
</table>

### `extractBits` (unsigned) ### {#extractBits-unsigned-builtin}
<table class='data builtin'>
  <tr algorithm="unsigned extract bits">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn extractBits(e: T,
                                        offset: u32,
                                        count: u32) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [UNSIGNEDINTEGRAL]
  <tr>
    <td>Description
    <td>Reads bits from an integer, without sign extension.

    When `T` is a scalar type, then:
    <ul>
    <li>`w` is the bit width of `T`
    <li>`o = min(offset, w)`
    <li>`c = min(count, w - o)`
    <li>The result is 0 if `c` is 0.
    <li>Otherwise, bits `0..c - 1` of the result are copied from bits
       `o..o + c - 1` of `e`.
       Other bits of the result are 0.
    </ul>
    [=Component-wise=] when `T` is a vector.

    If `count` + `offset` is greater than `w`, then:
    * It is a [=shader-creation error=] if `count` and `offset` are [=const-expressions=].
    * It is a [=pipeline-creation error=] if `count` and `offset` are [=override-expressions=].
</table>

### `faceForward` ### {#faceForward-builtin}
<table class='data builtin'>
  <tr algorithm="faceForward">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn faceForward(e1: T,
                                        e2: T,
                                        e3: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;AbstractFloat&gt;, vecN&lt;f32&gt;, or vecN&lt;f16&gt;
  <tr>
    <td>Description
    <td>Returns `e1` if `dot(e2, e3)` is negative, and `-e1` otherwise.
</table>

### `firstLeadingBit` (signed) ### {#firstLeadingBit-signed-builtin}
<table class='data builtin'>
  <tr algorithm="signed find most significant one bit">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn firstLeadingBit(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [SIGNEDINTEGRAL]
  <tr>
    <td>Description
    <td>For scalar `T`, the result is:
        <ul>
        <li>-1 if `e` is 0 or -1.
        <li>Otherwise the position of the most significant bit in
            `e` that is different from `e`'s sign bit.
        </ul>

        [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: Since signed integers use twos-complement representation,
the sign bit appears in the most significant bit position.

</table>

### `firstLeadingBit` (unsigned) ### {#firstLeadingBit-unsigned-builtin}
<table class='data builtin'>
  <tr algorithm="unsigned find most significant one bit">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn firstLeadingBit(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [UNSIGNEDINTEGRAL]
  <tr>
    <td>Description
    <td>For scalar `T`, the result is:
        <ul>
        <li>`T(-1)` if `e` is zero.
        <li>Otherwise the position of the most significant 1
            bit in `e`.
        </ul>
        [=Component-wise=] when `T` is a vector.
</table>

### `firstTrailingBit` ### {#firstTrailingBit-builtin}
<table class='data builtin'>
  <tr algorithm="find least significant one bit">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn firstTrailingBit(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [INTEGRAL]
  <tr>
    <td>Description
    <td>For scalar `T`, the result is:
        <ul>
        <li>`T(-1)` if `e` is zero.
        <li>Otherwise the position of the least significant 1
            bit in `e`.
        </ul>
        [=Component-wise=] when `T` is a vector.
</table>

### `floor` ### {#floor-builtin}
<table class='data builtin'>
  <tr algorithm="floor">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn floor(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the [=floor expression|floor=] of `e`.
    [=Component-wise=] when `T` is a vector.
</table>

### `fma` ### {#fma-builtin}
<table class='data builtin'>
  <tr algorithm="fma">
  <td style="width:10%">Overload
  <td class="nowrap">
    <xmp highlight=wgsl>
      @const @must_use fn fma(e1: T,
                              e2: T,
                              e3: T) -> T
    </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns `e1 * e2 + e3`.
    [=Component-wise=] when `T` is a vector.

    Note: The name `fma` is short for "fused multiply add".

    Note:
    The [[!IEEE-754|IEEE-754]] `fusedMultiplyAdd` operation computes the intermediate results
    as if with unbounded range and precision, and only the final result is rounded
    to the destination type.
    However, the [[#floating-point-accuracy]] rule for `fma` allows an implementation
    which performs an ordinary multiply to the target type followed by an ordinary addition.
    In this case the intermediate values may overflow or lose accuracy, and the overall
    operation is not "fused" at all.
</table>

### `fract` ### {#fract-builtin}
<table class='data builtin'>
  <tr algorithm="fract">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn fract(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the fractional part of `e`, computed as `e - floor(e)`.<br>
    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: Valid results are in the closed interval [0, 1.0].
For example, if `e` is a very small negative number, then `fract(e)` may be 1.0.

</table>

### `frexp` ### {#frexp-builtin}
<table class='data builtin'>
  <tr algorithm="scalar case, binary32, frexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn frexp(e: T) -> __frexp_result_f32
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32
  <tr>
    <td>Description
    <td>Splits `e` into a fraction and an exponent.

    * When `e` is zero, the fraction is zero.
    * When `e` is non-zero and normal, `e` &equals; `fraction * 2`<sup>`exponent`</sup>, where
        the fraction is in the range [0.5, 1.0) or (-1.0, -0.5].
    * Otherwise, `e` is denormalized, NaN, or infinite. The result fraction and exponent are [=indeterminate values=].

    Returns the `__frexp_result_f32` built-in structure, defined as follows:
    ```wgsl
struct __frexp_result_f32 {
  fract : f32, // fraction part
  exp : i32    // exponent part
}
    ```

    Note: A mnemonic for the name `frexp` is "**fr**action and **exp**onent".
  <tr>
    <td>
    <td>
    <div class='example wgsl function-scope' heading='frexp usage'>
    <xmp highlight=wgsl>
     // Infers result type
     let fraction_and_exponent = frexp(1.5);
     // Sets fraction_only to 0.75
     let fraction_only = frexp(1.5).fract;
    </xmp>
    </div>
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__frexp_result_f32`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="scalar case, binary16, frexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn frexp(e: T) -> __frexp_result_f16
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f16
  <tr>
    <td>Description
    <td>Splits `e` into a fraction and an exponent.

    * When `e` is zero, the fraction is zero.
    * When `e` is non-zero and normal, `e` &equals; `fraction * 2`<sup>`exponent`</sup>, where
        the fraction is in the range [0.5, 1.0) or (-1.0, -0.5].
    * Otherwise, `e` is denormalized, NaN, or infinite. The result fraction and exponent are [=indeterminate values=].

    Returns the `__frexp_result_f16` built-in structure, defined as if as follows:
    ```wgsl
struct __frexp_result_f16 {
  fract : f16, // fraction part
  exp : i32    // exponent part
}
    ```

    Note: A mnemonic for the name `frexp` is "**fr**action and **exp**onent".
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__frexp_result_f16`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="scalar case, abstract, frexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn frexp(e: T) -> __frexp_result_abstract
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat
  <tr>
    <td>Description
    <td>Splits `e` into a fraction and an exponent.

    * When `e` is zero, the fraction is zero.
    * When `e` is non-zero and normal, `e` &equals; `fraction * 2`<sup>`exponent`</sup>, where
        the fraction is in the range [0.5, 1.0) or (-1.0, -0.5].
    * When `e` is denormalized, the fraction and exponent are have unbounded error.
        The fraction may be any AbstractFloat value, and the exponent may be any AbstractInt value.

    Note: AbstractFloat expressions resulting in infinity or NaN cause a [=shader-creation error=].

    Returns the `__frexp_result_abstract` built-in structure, defined as follows:
    ```wgsl
struct __frexp_result_abstract {
  fract : AbstractFloat, // fraction part
  exp : AbstractInt      // exponent part
}
    ```

    Note: A mnemonic for the name `frexp` is "**fr**action and **exp**onent".
  <tr>
    <td>
    <td>
    <div class='example wgsl function-scope' heading='abstract frexp usage'>
    <xmp highlight=wgsl>
     // Infers result type
     const fraction_and_exponent = frexp(1.5);
     // Sets fraction_only to 0.75
     const fraction_only = frexp(1.5).fract;
    </xmp>
    </div>
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__frexp_result_abstract`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="vector case, binary32, frexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn frexp(e: T) -> __frexp_result_vecN_f32
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Splits components `ei` of `e` into a fraction and an exponent.

    * When `ei` is zero, the fraction is zero.
    * When `ei` is non-zero and normal, `ei` &equals; `fraction * 2`<sup>`exponent`</sup>, where
        the fraction is in the range [0.5, 1.0) or (-1.0, -0.5].
    * Otherwise, `ei` is NaN or infinite. The result fraction and exponent are [=indeterminate values=].

    Returns the `__frexp_result_vecN_f32` built-in structure, defined as follows:
    ```wgsl
struct __frexp_result_vecN_f32 {
  fract : vecN<f32>, // fraction part
  exp : vecN<i32>    // exponent part
}
    ```

    Note: A mnemonic for the name `frexp` is "**fr**action and **exp**onent".
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__frexp_result_vecN_f32`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="vector case, binary16, frexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn frexp(e: T) -> __frexp_result_vecN_f16
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;f16&gt;
  <tr>
    <td>Description
    <td>Splits components `ei` of `e` into a fraction and an exponent.

    * When `ei` is zero, the fraction is zero.
    * When `ei` is non-zero and normal, `ei` &equals; `fraction * 2`<sup>`exponent`</sup>, where
        the fraction is in the range [0.5, 1.0) or (-1.0, -0.5].
    * Otherwise, `ei` is NaN or infinite. The result fraction and exponent are [=indeterminate values=].

    Returns the `__frexp_result_vecN_f16` built-in structure, defined as if as follows:
    ```wgsl
struct __frexp_result_vecN_f16 {
  fract : vecN<f16>, // fraction part
  exp : vecN<i32>    // exponent part
}
    ```

    Note: A mnemonic for the name `frexp` is "**fr**action and **exp**onent".
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__frexp_result_vecN_f16`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="vector case, abstract, frexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn frexp(e: T) -> __frexp_result_vecN_abstract
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;AbstractFloat&gt;
  <tr>
    <td>Description
    <td>Splits components `ei` of `e` into a fraction and an exponent.

    * When `ei` is zero, the fraction is zero.
    * When `ei` is non-zero and normal, `ei` &equals; `fraction * 2`<sup>`exponent`</sup>, where
        the fraction is in the range [0.5, 1.0) or (-1.0, -0.5].
    * When `ei` is denormalized, the fraction and exponent are have unbounded error.
        The fraction may be any AbstractFloat value, and the exponent may be any AbstractInt value.

    Note: AbstractFloat expressions resulting in infinity or NaN cause a [=shader-creation error=].

    Returns the `__frexp_result_vecN_abstract` built-in structure, defined as follows:
    ```wgsl
struct __frexp_result_vecN_abstract {
  fract : vecN<AbstractFloat>, // fraction part
  exp : vecN<AbstractInt>      // exponent part
}
    ```

    Note: A mnemonic for the name `frexp` is "**fr**action and **exp**onent".
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__frexp_result_vecN_abstract`,
but a value may infer the type.

</table>

### `insertBits` ### {#insertBits-builtin}
<table class='data builtin'>
  <tr algorithm="insert bits">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn insertBits(e: T,
                                      newbits: T,
                                      offset: u32,
                                      count: u32) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [INTEGRAL]
  <tr>
    <td>Description
    <td>Sets bits in an integer.

    When `T` is a scalar type, then:
    <ul>
    <li>`w` is the bit width of `T`
    <li>`o = min(offset, w)`
    <li>`c = min(count, w - o)`
    <li>The result is `e` if `c` is 0.
    <li>Otherwise,
       bits `o..o + c - 1` of the result are copied from bits `0..c - 1` of `newbits`.
       Other bits of the result are copied from `e`.
    </ul>
    [=Component-wise=] when `T` is a vector.

    If `count` + `offset` is greater than `w`, then:
    * It is a [=shader-creation error=] if `count` and `offset` are [=const-expressions=].
    * It is a [=pipeline-creation error=] if `count` and `offset` are [=override-expressions=].
</table>

### `inverseSqrt` ### {#inverseSqrt-builtin}
<table class='data builtin'>
  <tr algorithm="inverseSqrt">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn inverseSqrt(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the reciprocal of `sqrt(e)`.
    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful if `e` &le; 0.
</table>

### `ldexp` ### {#ldexp-builtin}
<table class='data builtin'>
  <tr algorithm="ldexp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn ldexp(e1: T,
                                  e2: I) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]<br>
        `I` is [ALLSIGNEDINTEGRAL]<br>
        `I` is a vector if and only if `T` is a vector<br>
        `T` can only be [=type/abstract=] if `I` is also [=type/abstract=] and vice versa

        Note: If either parameter is [=type/concrete=] then the other parameter
        will undergo [=feasible automatic conversion|automatic conversion=] to
        a [=type/concrete=] type (if applicable) and the result will be a
        [=type/concrete=] type.
  <tr>
    <td>Description
    <td>Returns `e1 * 2`<sup>`e2`</sup>, except:
    * The result may be zero if `e2` + *bias* &le; 0.
    * If `e2` &gt; *bias* + 1
         * It is a [=shader-creation error=] if `e2` is a [=const-expression=].
         * It is a [=pipeline-creation error=] if `e2` is an [=override-expression=].
         * Otherwise the result is an [=indeterminate value=] for `T`.

    Here, *bias* is the exponent bias of the floating point format:
    * 15 for `f16`
    * 127 for `f32`
    * 1023 for AbstractFloat, when AbstractFloat is [[!IEEE-754|IEEE-754]] binary64

    If `x` is zero or a finite normal value for its type, then:

    <blockquote>
    x = ldexp(frexp(x).fract, frexp(x).exp)
    </blockquote>

    [=Component-wise=] when `T` is a vector.

    Note: A mnemonic for the name `ldexp` is "load exponent".
    The name may have been taken from the corresponding instruction in the floating point unit of
    the PDP-11.
</table>

### `length` ### {#length-builtin}
<table class='data builtin'>
  <tr algorithm="length">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn length(e: T) -> S
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the length of `e`.<br>
        Evaluates to the absolute value of `e` if `T` is [=scalar=].<br>
        Evaluates to `sqrt(e[0]`<sup>`2`</sup> `+ e[1]`<sup>`2`</sup> `+ ...)` if `T` is a vector type.

        Note: The scalar case may be evaluated as `sqrt(e * e)`,
        which may unnecessarily overflow or lose accuracy.
</table>

### `log` ### {#log-builtin}
<table class='data builtin'>
  <tr algorithm="log">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn log(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the natural logarithm of `e`.
    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful if `e` &lt; 0.
</table>

### `log2` ### {#log2-builtin}
<table class='data builtin'>
  <tr algorithm="log2">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn log2(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the base-2 logarithm of `e`.
    [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The result is not mathematically meaningful if `e` &lt; 0.
</table>

### `max` ### {#max-float-builtin}
<table class='data builtin'>
  <tr algorithm="max">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn max(e1: T,
                                e2: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLNUMERICDECL]
  <tr>
    <td>Description
    <td>Returns `e2` if `e1` is less than `e2`, and `e1` otherwise.
    [=Component-wise=] when `T` is a vector.

    If `e1` and `e2` are floating-point values, then:
    * If both `e1` and `e2` are denormalized, then the result may be *either* value.
    * If one operand is a NaN, the other is returned.
    * If both operands are NaNs, a NaN is returned.
</table>

### `min` ### {#min-float-builtin}
<table class='data builtin'>
  <tr algorithm="min">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn min(e1: T,
                                e2: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLNUMERICDECL]
  <tr>
    <td>Description
    <td>Returns `e2` if `e2` is less than `e1`, and `e1` otherwise.
    [=Component-wise=] when `T` is a vector.

    If `e1` and `e2` are floating-point values, then:
    * If both `e1` and `e2` are denormalized, then the result may be *either* value.
    * If one operand is a NaN, the other is returned.
    * If both operands are NaNs, a NaN is returned.
</table>

### `mix` ### {#mix-builtin}
<table class='data builtin'>
  <tr algorithm="mix all same type operands">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn mix(e1: T,
                                e2: T,
                                e3: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the linear blend of `e1` and `e2` (e.g. `e1 * (1 - e3) + e2 * e3`).
    [=Component-wise=] when `T` is a vector.
</table>

<table class='data builtin'>
  <tr algorithm="vector mix with scalar blending factor">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn mix(e1: T2,
                                e2: T2,
                                e3: T) -> T2
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat, f32, or f16<br>
        `T2` is vecN&lt;T&gt;
  <tr>
    <td>Description
    <td>Returns the component-wise linear blend of `e1` and `e2`,
        using scalar blending factor `e3` for each component.<br>
        Same as `mix(e1, e2, T2(e3))`.
</table>

### `modf` ### {#modf-builtin}
<table class='data builtin'>
  <tr algorithm="scalar case, binary32, modf">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn modf(e: T) -> __modf_result_f32
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32
  <tr>
    <td>Description
    <td>Splits `e` into fractional and whole number parts.

    The whole part is [[#trunc-builtin|trunc]](`e`), and the fractional part is `e` - [[#trunc-builtin|trunc]](`e`).

    Returns the `__modf_result_f32` built-in structure, defined as follows:
    ```wgsl
struct __modf_result_f32 {
  fract : f32, // fractional part
  whole : f32  // whole part
}
    ```
  <tr>
    <td>
    <td>
    <div class='example wgsl function-scope' heading='modf usage'>
    <xmp highlight=wgsl>
     // Infers result type
     let fract_and_whole = modf(1.5);
     // Sets fract_only to 0.5
     let fract_only = modf(1.5).fract;
     // Sets whole_only to 1.0
     let whole_only = modf(1.5).whole;
    </xmp>
    </div>
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__modf_result_f32`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="scalar case, binary16, modf">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn modf(e: T) -> __modf_result_f16
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f16
  <tr>
    <td>Description
    <td>Splits `e` into fractional and whole number parts.

    The whole part is [[#trunc-builtin|trunc]](`e`), and the fractional part is `e` - [[#trunc-builtin|trunc]](`e`).

    Returns the `__modf_result_f16` built-in structure, defined as if as follows:
    ```wgsl
struct __modf_result_f16 {
  fract : f16, // fractional part
  whole : f16  // whole part
}
    ```
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__modf_result_f16`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="scalar case, abstract, modf">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn modf(e: T) -> __modf_result_abstract
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat
  <tr>
    <td>Description
    <td>Splits `e` into fractional and whole number parts.

    The whole part is [[#trunc-builtin|trunc]](`e`), and the fractional part is `e` - [[#trunc-builtin|trunc]](`e`).

    Returns the `__modf_result_abstract` built-in structure, defined as follows:
    ```wgsl
struct __modf_result_abstract {
  fract : AbstractFloat, // fractional part
  whole : AbstractFloat  // whole part
}
    ```
  <tr>
    <td>
    <td>
    <div class='example wgsl function-scope' heading='modf abstract usage'>
    <xmp highlight=wgsl>
     // Infers result type
     const fract_and_whole = modf(1.5);
     // Sets fract_only to 0.5
     const fract_only = modf(1.5).fract;
     // Sets whole_only to 1.0
     const whole_only = modf(1.5).whole;
    </xmp>
    </div>
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__modf_result_abstract`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="vector case, binary32, modf">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn modf(e: T) -> __modf_result_vecN_f32
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Splits the components of `e` into fractional and whole number parts.

    The `i`'th component of the whole and fractional parts equal the whole and fractional parts
    of `modf(e[i])`.

    Returns the `__modf_result_vecN_f32` built-in structure, defined as follows:
    ```wgsl
struct __modf_result_vecN_f32 {
  fract : vecN<f32>, // fractional part
  whole : vecN<f32>  // whole part
}
    ```
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__modf_result_vecN_f32`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="vector case, binary16, modf">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn modf(e: T) -> __modf_result_vecN_f16
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;f16&gt;
  <tr>
    <td>Description
    <td>Splits the components of `e` into fractional and whole number parts.

    The `i`'th component of the whole and fractional parts equal the whole and fractional parts
    of `modf(e[i])`.

    Returns the `__modf_result_vecN_f16` built-in structure, defined as if as follows:
    ```wgsl
struct __modf_result_vecN_f16 {
  fract : vecN<f16>, // fractional part
  whole : vecN<f16>  // whole part
}
    ```
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__modf_result_vecN_f16`,
but a value may infer the type.

</table>

<table class='data builtin'>
  <tr algorithm="vector case, abstract, modf">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn modf(e: T) -> __modf_result_vecN_abstract
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;AbstractFloat&gt;
  <tr>
    <td>Description
    <td>Splits the components of `e` into fractional and whole number parts.

    The `i`'th component of the whole and fractional parts equal the whole and fractional parts
    of `modf(e[i])`.

    Returns the `__modf_result_vecN_abstract` built-in structure, defined as follows:
    ```wgsl
struct __modf_result_vecN_abstract {
  fract : vecN<AbstractFloat>, // fractional part
  whole : vecN<AbstractFloat>  // whole part
}
    ```
  <tr>
    <td>
    <td>

Note: A value cannot be explicitly declared with the type `__modf_result_vecN_abstract`,
but a value may infer the type.

</table>

### `normalize` ### {#normalize-builtin}
<table class='data builtin'>
  <tr algorithm="vector case, normalize">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn normalize(e: vecN<T> ) -> vecN<T>
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat, f32, or f16
  <tr>
    <td>Description
    <td>Returns a unit vector in the same direction as `e`.
</table>

### `pow` ### {#pow-builtin}
<table class='data builtin'>
  <tr algorithm="pow">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pow(e1: T,
                                e2: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns `e1` raised to the power `e2`.
    [=Component-wise=] when `T` is a vector.
</table>

### `quantizeToF16` ### {#quantizeToF16-builtin}
<table class='data builtin'>
  <tr algorithm="quantize to f16">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn quantizeToF16(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Quantizes a 32-bit floating point value `e` as if `e` were converted to
        a [[!IEEE-754|IEEE 754]] binary16 value, and then converted back to a
        IEEE 754 binary32 value.

        If `e` is outside the finite range of binary16, then:
        * It is a [=shader-creation error=] if `e` is a [=const-expression=].
        * It is a [=pipeline-creation error=] if `e` is an [=override-expression=].
        * Otherwise the result is an [=indeterminate value=] for `T`.

        The intermediate binary16 value may be [=flushed to zero=], i.e. the final
        result may be zero if the intermediate binary16 value is denormalized.

        See [[#floating-point-conversion]].

        [=Component-wise=] when `T` is a vector.
  <tr>
    <td>
    <td>

Note: The vec2&lt;f32&gt; case is the same as `unpack2x16float(pack2x16float(e))`.

</table>

### `radians` ### {#radians-builtin}
<table class='data builtin'>
  <tr algorithm="radians">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn radians(e1: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Converts degrees to radians, approximating `e1`&nbsp;&times;&nbsp;&pi;&nbsp;&div;&nbsp;180.
    [=Component-wise=] when `T` is a vector
</table>

### `reflect` ### {#reflect-builtin}
<table class='data builtin'>
  <tr algorithm="reflect">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn reflect(e1: T,
                                    e2: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;AbstractFloat&gt;, vecN&lt;f32&gt;, or vecN&lt;f16&gt;
  <tr>
    <td>Description
    <td>For the incident vector `e1` and surface orientation `e2`, returns the reflection direction
    `e1 - 2 * dot(e2, e1) * e2`.
</table>

### `refract` ### {#refract-builtin}
<table class='data builtin'>
  <tr algorithm="refract">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn refract(e1: T,
                                    e2: T,
                                    e3: I) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is vecN&lt;I&gt;<br>
        `I` is AbstractFloat, f32, or f16
  <tr>
    <td>Description
    <td>For the incident vector `e1` and surface normal `e2`, and the ratio of
    indices of refraction `e3`,
    let `k = 1.0 - e3 * e3 * (1.0 - dot(e2, e1) * dot(e2, e1))`.
    If `k < 0.0`, returns the refraction vector 0.0, otherwise return the refraction vector
    `e3 * e1 - (e3 * dot(e2, e1) + sqrt(k)) * e2`.
</table>

### `reverseBits` ### {#reverseBits-builtin}
<table class='data builtin'>
  <tr algorithm="bit reversal">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn reverseBits(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is [INTEGRAL]
  <tr>
    <td>Description
    <td>Reverses the bits in `e`:  The bit at position `k` of the result equals the
        bit at position `31 -k` of `e`.<br>
        [=Component-wise=] when `T` is a vector.
</table>

### `round` ### {#round-builtin}
<table class='data builtin'>
  <tr algorithm="round">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn round(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Result is the integer `k` nearest to `e`, as a floating point value.<br>
        When `e` lies halfway between integers `k` and `k + 1`,
        the result is `k` when `k` is even, and `k + 1` when `k` is odd.<br>
        [=Component-wise=] when `T` is a vector.
</table>

### `saturate` ### {#saturate-float-builtin}
<table class='data builtin'>
  <tr algorithm="saturate">
  <td style="width:10%">Overload
  <td class="nowrap">
    <xmp highlight=wgsl>@const @must_use fn saturate(e: T) -> T</xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns `clamp(e, 0.0, 1.0)`.
    [=Component-wise=] when `T` is a vector.
</table>

### `sign` ### {#sign-builtin}
<table class='data builtin'>
  <tr algorithm="numeric sign">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn sign(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLSIGNEDNUMERICDECL]
  <tr>
    <td>Description
    <td>Result is:
      <ul>
      <li> 1 when `e` &gt; 0
      <li> 0 when `e` = 0
      <li> -1 when `e` &lt; 0
      </ul>

    [=Component-wise=] when `T` is a vector.
</table>

### `sin` ### {#sin-builtin}
<table class='data builtin'>
  <tr algorithm="sin">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn sin(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the sine of `e`, where `e` is in radians.
    [=Component-wise=] when `T` is a vector.
</table>

### `sinh` ### {#sinh-builtin}
<table class='data builtin'>
  <tr algorithm="sinh">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn sinh(a: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the hyperbolic sine of `a`, where `a` is a [=hyperbolic angle=].
    Approximates the pure mathematical function
    (*e*<sup>a</sup> &minus; *e*<sup>&minus;a</sup>)&divide;2,
    but not necessarily computed that way.

    [=Component-wise=] when `T` is a vector.
</table>

### `smoothstep` ### {#smoothstep-builtin}
<table class='data builtin'>
  <tr algorithm="smoothstep">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn smoothstep(low: T,
                                       high: T,
                                       x: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the smooth Hermite interpolation between 0 and 1.
    [=Component-wise=] when `T` is a vector.

    For scalar `T`, the result is
    `t * t * (3.0 - 2.0 * t)`,<br>
    where `t = clamp((x - low) / (high - low), 0.0, 1.0)`.

    If `low >= high`:
    * It is a [=shader-creation error=] if `low` and `high` are [=const-expressions=].
    * It is a [=pipeline-creation error=] if `low` and `high` are [=override-expressions=].
</table>

### `sqrt` ### {#sqrt-builtin}
<table class='data builtin'>
  <tr algorithm="sqrt">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn sqrt(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the square root of `e`.
    [=Component-wise=] when `T` is a vector.
</table>

### `step` ### {#step-builtin}
<table class='data builtin'>
  <tr algorithm="step">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn step(edge: T,
                                 x: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns 1.0 if `edge` &le; `x`, and 0.0 otherwise.
    [=Component-wise=] when `T` is a vector.
</table>

### `tan` ### {#tan-builtin}
<table class='data builtin'>
  <tr algorithm="tan">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn tan(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the tangent of `e`, where `e` is in radians.
    [=Component-wise=] when `T` is a vector.
</table>

### `tanh` ### {#tanh-builtin}
<table class='data builtin'>
  <tr algorithm="tanh">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn tanh(a: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns the hyperbolic tangent of `a`, where `a` is a [=hyperbolic angle=].
    Approximates the pure mathematical function
    (*e*<sup>a</sup> &minus; *e*<sup>&minus;a</sup>) &divide; (*e*<sup>a</sup> + *e*<sup>&minus;a</sup>)
    but not necessarily computed that way.

    [=Component-wise=] when `T` is a vector.
</table>

### `transpose` ### {#transpose-builtin}
<table class='data builtin'>
  <tr algorithm="transpose">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn transpose(e: matRxC<T>) -> matCxR<T>
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is AbstractFloat, f32, or f16
  <tr>
    <td>Description
    <td>Returns the transpose of `e`.
</table>

### `trunc` ### {#trunc-builtin}
<table class='data builtin'>
  <tr algorithm="trunc">
        <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn trunc(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>[ALLFLOATINGDECL]
  <tr>
    <td>Description
    <td>Returns [=truncate=](`e`), the nearest whole number whose absolute value
    is less than or equal to the absolute value of `e`.
    [=Component-wise=] when `T` is a vector.
</table>

## Derivative Built-in Functions ## {#derivative-builtin-functions}

See [[#derivatives]].

Calls to these functions:
* [=shader-creation error|Must=] only be used in a [=fragment=] shader stage.
* [=Trigger=] a [=trigger/derivative_uniformity=] [=diagnostic=] if [=uniformity analysis=]
    cannot prove the call is in [=uniform control flow=].

### `dpdx` ### {#dpdx-builtin}
<table class='data builtin'>
  <tr algorithm="dpdx">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn dpdx(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Partial derivative of `e` with respect to window x coordinates.
    The result is the same as either `dpdxFine(e)` or `dpdxCoarse(e)`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `dpdxCoarse` ### {#dpdxCoarse-builtin}
<table class='data builtin'>
  <tr algorithm="dpdxCoarse">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn dpdxCoarse(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns the partial derivative of `e` with respect to window x coordinates using local differences.
    This may result in fewer unique positions than `dpdxFine(e)`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `dpdxFine` ### {#dpdxFine-builtin}
<table class='data builtin'>
  <tr algorithm="dpdxFine">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn dpdxFine(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns the partial derivative of `e` with respect to window x coordinates.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `dpdy` ### {#dpdy-builtin}
<table class='data builtin'>
  <tr algorithm="dpdy">
  <td style="width:10%">Overload
  <td class="nowrap">
    <xmp highlight=wgsl>@must_use fn dpdy(e: T) -> T</xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Partial derivative of `e` with respect to window y coordinates.
    The result is the same as either `dpdyFine(e)` or `dpdyCoarse(e)`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `dpdyCoarse` ### {#dpdyCoarse-builtin}
<table class='data builtin'>
  <tr algorithm="dpdyCoarse">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn dpdyCoarse(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns the partial derivative of `e` with respect to window y coordinates using local differences.
    This may result in fewer unique positions than `dpdyFine(e)`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `dpdyFine` ### {#dpdyFine-builtin}
<table class='data builtin'>
  <tr algorithm="dpdyFine">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn dpdyFine(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns the partial derivative of `e` with respect to window y coordinates.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `fwidth` ### {#fwidth-builtin}
<table class='data builtin'>
  <tr algorithm="fwidth">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn fwidth(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns `abs(dpdx(e)) + abs(dpdy(e))`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `fwidthCoarse` ### {#fwidthCoarse-builtin}
<table class='data builtin'>
  <tr algorithm="fwidthCoarse">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn fwidthCoarse(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns `abs(dpdxCoarse(e)) + abs(dpdyCoarse(e))`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

### `fwidthFine` ### {#fwidthFine-builtin}
<table class='data builtin'>
  <tr algorithm="fwidthFine">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn fwidthFine(e: T) -> T
      </xmp>
  <tr>
    <td style="width:10%">Parameterization
    <td>`T` is f32 or vecN&lt;f32&gt;
  <tr>
    <td>Description
    <td>Returns `abs(dpdxFine(e)) + abs(dpdyFine(e))`.

    Returns an [=indeterminate value=] if called in [=uniform control flow|non-uniform control flow=].
</table>

## Texture Built-in Functions ## {#texture-builtin-functions}

Parameter values [=shader-creation error|must=] be valid for the respective texture types.

### `textureDimensions` ### {#texturedimensions}

Returns the dimensions of a texture, or texture's mip level in texels.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureDimensions 1d">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br>
        <var ignore>F</var> is a [=texel format=]<br>
        <var ignore>A</var> is an [=access mode=]<br><br>
        |T| is `texture_1d<ST>` or `texture_storage_1d<F,A>`
    <td>
      <xmp highlight=wgsl>@must_use fn textureDimensions(t: T) -> u32</xmp>

  <tr algorithm="textureDimensions 1d level">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br><br>
        |T| is `texture_1d<ST>`

        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureDimensions(t: T,
                                       level: L) -> u32
      </xmp>

  <tr algorithm="textureDimensions 2d">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br>
        <var ignore>F</var> is a [=texel format=]<br>
        <var ignore>A</var> is an [=access mode=]<br><br>
        |T| is `texture_2d<ST>`, `texture_2d_array<ST>`, `texture_cube<ST>`,
               `texture_cube_array<ST>`, `texture_multisampled_2d<ST>`,
               `texture_depth_2d`, `texture_depth_2d_array`, `texture_depth_cube`,
               `texture_depth_cube_array`, `texture_depth_multisampled_2d`,
               `texture_storage_2d<F,A>`, `texture_storage_2d_array<F,A>`,
               or `texture_external`
    <td>
      <xmp highlight=wgsl>@must_use fn textureDimensions(t: T) -> vec2<u32></xmp>

  <tr algorithm="textureDimensions 2d level">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br><br>
        |T| is `texture_2d<ST>`, `texture_2d_array<ST>`, `texture_cube<ST>`,
               `texture_cube_array<ST>`, `texture_depth_2d`, `texture_depth_2d_array`,
               `texture_depth_cube`, or `texture_depth_cube_array`

        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureDimensions(t: T,
                                       level: L) -> vec2<u32>
      </xmp>

  <tr algorithm="textureDimensions 3d">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br>
        <var ignore>F</var> is a [=texel format=]<br>
        <var ignore>A</var> is an [=access mode=]<br><br>
        |T| is `texture_3d<ST>` or `texture_storage_3d<F,A>`
    <td>
      <xmp highlight=wgsl>@must_use fn textureDimensions(t: T) -> vec3<u32></xmp>

  <tr algorithm="textureDimensions 3d level">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br><br>
        |T| is `texture_3d<ST>`

        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureDimensions(t: T,
                                       level: L) -> vec3<u32>
      </xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [sampled](#sampled-texture-type),
  [multisampled](#multisampled-texture-type), [depth](#texture-depth),
  [storage](#texture-storage), or [external](#external-texture-type) texture.
  <tr><td>`level`<td>
  The [=mip level=], with level 0 containing a full size version of the texture.<br>
  If omitted, the dimensions of level 0 are returned.
</table>

**Returns:**

The coordinate dimensions of the texture.

That is, the result provides the integer bounds on the coordinates of the [=logical texel address=],
excluding the [=texture/mip level count=], [=texture/array size=], and [=texture/sample count=].

For textures based on cubes, the results are the dimensions of each face of the cube.
Cube faces are square, so the x and y components of the result are equal.

If `level` is outside the range `[0, textureNumLevels(t))` then an [=indeterminate value=]
for the return type may be returned.

### `textureGather` ### {#texturegather}

A <dfn noexport>texture gather</dfn> operation reads from a 2D, 2D array, cube, or cube array texture,
computing a four-component vector as follows:
* Find the four texels that would be used in a sampling operation with linear filtering,
    from [=mip level=] 0:
    * Use the specified coordinate, array index (when present), and offset (when present).
    * The texels are adjacent, forming a square, when considering their texture space coordinates (*u*,*v*).
    * Selected texels at the texture edge, cube face edge, or cube corners are handled
        as in ordinary texture sampling.
* For each texel, read one channel and convert it into a scalar value.
    * For non-depth textures, a zero-based `component` parameter specifies the channel to use.
        * If the texture format supports the specified channel, i.e. has more than `component` channels:
             * Yield scalar value `v[component]` when the texel value is `v`.
        * Otherwise:
             * Yield 0.0 when `component` is 1 or 2.
             * Yield 1.0 when `component` is 3 (the alpha channel).
    * For [=type/depth textures=], yield the texel value. (Depth textures only have one channel.)
* Yield the four-component vector, arranging scalars produced by the previous step into components
    according to the relative coordinates of the texels, as follows:
    * <table>
        <thead class='data'><td>Result component<td>Relative texel coordinate</thead>
        <tr><td>x<td>(*u*<sub>min</sub>,*v*<sub>max</sub>)
        <tr><td>y<td>(*u*<sub>max</sub>,*v*<sub>max</sub>)
        <tr><td>z<td>(*u*<sub>max</sub>,*v*<sub>min</sub>)
        <tr><td>w<td>(*u*<sub>min</sub>,*v*<sub>min</sub>)
        </table>

TODO: The four texels are the "sample footprint" that should be described by the WebGPU spec.
https://github.com/gpuweb/gpuweb/issues/2343

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureGather 2d">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(component: C,
                                   t: texture_2d<ST>,
                                   s: sampler,
                                   coords: vec2<f32>) -> vec4<ST>
      </xmp>

  <tr algorithm="textureGather 2d offset">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(component: C,
                                   t: texture_2d<ST>,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   offset: vec2<i32>) -> vec4<ST>
      </xmp>

  <tr algorithm="textureGather 2d array">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(component: C,
                                   t: texture_2d_array<ST>,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A) -> vec4<ST>
      </xmp>

  <tr algorithm="textureGather 2d array offset">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(component: C,
                                   t: texture_2d_array<ST>,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A,
                                   offset: vec2<i32>) -> vec4<ST>
      </xmp>

  <tr algorithm="textureGather cube">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(component: C,
                                   t: texture_cube<ST>,
                                   s: sampler,
                                   coords: vec3<f32>) -> vec4<ST>
      </xmp>

  <tr algorithm="textureGather cube array">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(component: C,
                                   t: texture_cube_array<ST>,
                                   s: sampler,
                                   coords: vec3<f32>,
                                   array_index: A) -> vec4<ST>
      </xmp>

  <tr algorithm="textureGather 2d depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(t: texture_depth_2d,
                                   s: sampler,
                                   coords: vec2<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGather 2d depth offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(t: texture_depth_2d,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGather cube depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(t: texture_depth_cube,
                                   s: sampler,
                                   coords: vec3<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGather 2d depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(t: texture_depth_2d_array,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGather 2d depth array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(t: texture_depth_2d_array,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A,
                                   offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGather cube depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGather(t: texture_depth_cube_array,
                                   s: sampler,
                                   coords: vec3<f32>,
                                   array_index: A) -> vec4<f32>
      </xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`component`<td>
  Only applies to non-depth textures.
  <br>The index of the channel to read from the selected texels.
  <br>When provided, the `component` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `1`).<br>
  Its value must be at least 0 and at most 3.
  Values outside of this range will result in a [=shader-creation error=].
  <tr><td>`t`<td>
  The [sampled](#sampled-texture-type) or [depth](#texture-depth) texture to read from.
  <tr><td>`s`<td>
  The [sampler type](#sampler-type).
  <tr><td>`coords`<td>
  The texture coordinates.
  <tr><td>`array_index`<td>
  The 0-based texture array index.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

A four component vector with components extracted from the specified channel from the selected texels, as described above.

<div class='example wgsl global-scope' heading="Gather components from texels in 2D texture">
  <xmp highlight=wgsl>
    @group(0) @binding(0) var t: texture_2d<f32>;
    @group(0) @binding(1) var dt: texture_depth_2d;
    @group(0) @binding(2) var s: sampler;

    fn gather_x_components(c: vec2<f32>) -> vec4<f32> {
      return textureGather(0,t,s,c);
    }
    fn gather_y_components(c: vec2<f32>) -> vec4<f32> {
      return textureGather(1,t,s,c);
    }
    fn gather_z_components(c: vec2<f32>) -> vec4<f32> {
      return textureGather(2,t,s,c);
    }
    fn gather_depth_components(c: vec2<f32>) -> vec4<f32> {
      return textureGather(dt,s,c);
    }
  </xmp>
</div>

### `textureGatherCompare` ### {#texturegathercompare}

A <dfn noexport>texture gather compare</dfn> operation performs a depth comparison on four texels in a depth
texture and collects the results into a single vector, as follows:

* Find the four texels that would be used in a depth sampling operation with linear filtering,
    from [=mip level=] 0:
    * Use the specified coordinate, array index (when present), and offset (when present).
    * The texels are adjacent, forming a square, when considering their texture space coordinates (*u*,*v*).
    * Selected texels at the texture edge, cube face edge, or cube corners are handled
        as in ordinary texture sampling.
* For each texel, perform a comparison against the depth reference value,
    yielding a 0.0 or 1.0 value, as controlled by the comparison sampler parameters.
* Yield the four-component vector where the components are the comparison results with the texels with
       relative texel coordinates as follows:
    * <table>
        <thead class='data'><td>Result component<td>Relative texel coordinate</thead>
        <tr><td>x<td>(*u*<sub>min</sub>,*v*<sub>max</sub>)
        <tr><td>y<td>(*u*<sub>max</sub>,*v*<sub>max</sub>)
        <tr><td>z<td>(*u*<sub>max</sub>,*v*<sub>min</sub>)
        <tr><td>w<td>(*u*<sub>min</sub>,*v*<sub>min</sub>)
        </table>

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureGatherCompare 2d depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGatherCompare(t: texture_depth_2d,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          depth_ref: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGatherCompare 2d depth offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGatherCompare(t: texture_depth_2d,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          depth_ref: f32,
                                          offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGatherCompare 2d depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          array_index: A,
                                          depth_ref: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGatherCompare 2d depth array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          array_index: A,
                                          depth_ref: f32,
                                          offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGatherCompare 2d depth cube">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGatherCompare(t: texture_depth_cube,
                                          s: sampler_comparison,
                                          coords: vec3<f32>,
                                          depth_ref: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureGatherCompare 2d depth cube array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureGatherCompare(t: texture_depth_cube_array,
                                          s: sampler_comparison,
                                          coords: vec3<f32>,
                                          array_index: A,
                                          depth_ref: f32) -> vec4<f32>
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [depth](#texture-depth) texture to read from.
  <tr><td>`s`<td>
  The [sampler comparison](#sampler-type).
  <tr><td>`coords`<td>
  The texture coordinates.
  <tr><td>`array_index`<td>
  The 0-based texture array index.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`depth_ref`<td>
  The reference value to compare the sampled depth value against.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

A four component vector with comparison result for the selected texels, as described above.

<div class='example wgsl global-scope' heading="Gather depth comparison">
  <xmp highlight=wgsl>
    @group(0) @binding(0) var dt: texture_depth_2d;
    @group(0) @binding(1) var s: sampler;

    fn gather_depth_compare(c: vec2<f32>, depth_ref: f32) -> vec4<f32> {
      return textureGatherCompare(dt,s,c,depth_ref);
    }
  </xmp>
</div>

### `textureLoad` ### {#textureload}

Reads a single texel from a texture without sampling or filtering.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureLoad 1d">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_1d<ST>,
                                 coords: C,
                                 level: L) -> vec4<ST>
      </xmp>

  <tr algorithm="textureLoad 2d">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_2d<ST>,
                                 coords: vec2<C>,
                                 level: L) -> vec4<ST>
      </xmp>

  <tr algorithm="textureLoad 2d array">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_2d_array<ST>,
                                coords: vec2<C>,
                                array_index: A,
                                level: L) -> vec4<ST>
      </xmp>

  <tr algorithm="textureLoad 3d">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_3d<ST>,
                                 coords: vec3<C>,
                                 level: L) -> vec4<ST>
      </xmp>

  <tr algorithm="textureLoad 2d multisampled">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>S</var> is [=i32=], or [=u32=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_multisampled_2d<ST>,
                                 coords: vec2<C>,
                                 sample_index: S)-> vec4<ST>
      </xmp>

  <tr algorithm="textureLoad 2d depth">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_depth_2d,
                                 coords: vec2<C>,
                                 level: L) -> f32
      </xmp>

  <tr algorithm="textureLoad 2d depth array">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_depth_2d_array,
                                 coords: vec2<C>,
                                 array_index: A,
                                 level: L) -> f32
      </xmp>

<tr algorithm="textureLoad 2d depth multisampled">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>S</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_depth_multisampled_2d,
                                 coords: vec2<C>,
                                 sample_index: S)-> f32
      </xmp>

  <tr algorithm="textureLoad external">
    <td><var ignore>C</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t: texture_external,
                                 coords: vec2<C>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureLoad 1d storage">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/read=] or [=access/read_write=]<br>
        <var ignore>CF</var> depends on the storage texel format <var ignore>F</var>.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t : texture_storage_1d<F, AM>,
                                 coords : C) -> vec4<CF>
      </xmp>

  <tr algorithm="textureLoad 2d storage">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/read=] or [=access/read_write=]<br>
        <var ignore>CF</var> depends on the storage texel format <var ignore>F</var>.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t : texture_storage_2d<F, AM>,
                                 coords : vec2<C>) -> vec4<CF>
      </xmp>

  <tr algorithm="textureLoad 2d array storage">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/read=] or [=access/read_write=]<br>
        <var ignore>A</var> is [=i32=] or [=u32=]<br>
        <var ignore>CF</var> depends on the storage texel format <var ignore>F</var>.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t : texture_storage_2d_array<F, AM>,
                                 coords : vec2<C>,
                                 array_index : A) -> vec4<CF>
      </xmp>

  <tr algorithm="textureLoad 3d storage">
    <td><var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/read=] or [=access/read_write=]<br>
        <var ignore>CF</var> depends on the storage texel format <var ignore>F</var>.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureLoad(t : texture_storage_3d<F, AM>,
                                 coords : vec3<C>) -> vec4<CF>
      </xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture|sampled=],
  [=type/multisampled texture|multisampled=],
  [=type/depth texture|depth=],
  [=type/storage texture|storage=], or
  [=type/external texture|external=]
  texture
  <tr><td>`coords`<td>
  The 0-based texel coordinate.
  <tr><td>`array_index`<td>
  The 0-based texture array index.
  <tr><td>`level`<td>
  The [=mip level=], with level 0 containing a full size version of the texture.
  <tr><td>`sample_index`<td>
  The 0-based sample index of the [=type/multisampled texture=].
</table>

**Returns:**

The unfiltered texel data.

The [=logical texel address=] is invalid if:
* any element of `coords` is outside the range `[0, textureDimensions(t, level))`
    for the corresponding element, or
* `array_index` is outside the range `[0, textureNumLayers(t))`, or
* `level` is outside the range `[0, textureNumLevels(t))`, or
* `sample_index` is outside the range `[0, textureNumSamples(s))`

If the logical texel addresss is invalid, the built-in function returns one of:
* The data for some texel within bounds of the texture
* A vector (0,0,0,0) or (0,0,0,1) of the appropriate type for non-depth textures
* 0.0 for depth textures

### `textureNumLayers` ### {#texturenumlayers}

Returns the number of layers (elements) of an [=texture/arrayed=] texture.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="texturenumlayers">
    <td><var ignore>F</var> is a [=texel format=]<br>
        <var ignore>A</var> is an [=access mode=]<br>
        <var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br><br>
        <var ignore>T</var> is `texture_2d_array<ST>`, `texture_cube_array<ST>`,
                               `texture_depth_2d_array`, `texture_depth_cube_array`,
                               or `texture_storage_2d_array<F,A>`
    <td>
      <xmp highlight=wgsl>@must_use fn textureNumLayers(t: T) -> u32</xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture|sampled=],
  [=type/depth texture|depth=], or
  [=type/storage texture=] array texture.
</table>

**Returns:**

If the texture is based on cubes, returns the number of cubes in the cube arrayed texture.

Otherwise returns the number of layers (homogeneous grids of texels) in the arrayed texture.

### `textureNumLevels` ### {#texturenumlevels}

Returns the number of mip levels of a texture.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="texturenumlevels">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br><br>
        <var ignore>T</var> is `texture_1d<ST>`, `texture_2d<ST>`,
                               `texture_2d_array<ST>`, `texture_3d<ST>`,
                               `texture_cube<ST>`, `texture_cube_array<ST>`,
                               `texture_depth_2d`, `texture_depth_2d_array`,
                               `texture_depth_cube`, or `texture_depth_cube_array`
    <td>
      <xmp highlight=wgsl>@must_use fn textureNumLevels(t: T) -> u32</xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture|sampled=] or [=type/depth texture|depth=] texture.
</table>

**Returns:**

The [=texture/mip level count=] for the texture.


### `textureNumSamples` ### {#texturenumsamples}

Returns the number samples per texel in a [=type/multisampled texture=].

<table class='data'>
  <thead>
    <tr><td style="width:45%">Parameterization<th>Overload
  </thead>
  <tr algorithm="texturenumsamples">
    <td><var ignore>ST</var> is [=i32=], [=u32=], or [=f32=]<br><br>
        <var ignore>T</var> is `texture_multisampled_2d<ST>`
                                or `texture_depth_multisampled_2d`
    <td>
      <xmp highlight=wgsl>@must_use fn textureNumSamples(t: T) -> u32</xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/multisampled texture=].
</table>

**Returns:**

The [=texture/sample count=] for the [=type/multisampled texture=].


### `textureSample` ### {#texturesample}

Samples a texture.

[=shader-creation error|Must=] only be used in a [=fragment=] shader stage.

If [=uniformity analysis=] cannot prove a call to this function is in [=uniform control flow=],
then a [=trigger/derivative_uniformity=] [=diagnostic=] is [=triggered=].

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureSample 1d">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_1d<f32>,
                                   s: sampler,
                                   coords: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 2d">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_2d<f32>,
                                   s: sampler,
                                   coords: vec2<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 2d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_2d<f32>,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 2d array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_2d_array<f32>,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 2d array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_2d_array<f32>,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A,
                                   offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 3d">
    <td><var ignore>T</var> is `texture_3d<f32>`, or `texture_cube<f32>`
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: T,
                                   s: sampler,
                                   coords: vec3<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 3d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_3d<f32>,
                                   s: sampler,
                                   coords: vec3<f32>,
                                   offset: vec3<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample cube array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_cube_array<f32>,
                                   s: sampler,
                                   coords: vec3<f32>,
                                   array_index: A) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSample 2d depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_depth_2d,
                                   s: sampler,
                                   coords: vec2<f32>) -> f32
      </xmp>

  <tr algorithm="textureSample 2d depth offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_depth_2d,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSample 2d depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_depth_2d_array,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A) -> f32
      </xmp>

  <tr algorithm="textureSample 2d depth array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_depth_2d_array,
                                   s: sampler,
                                   coords: vec2<f32>,
                                   array_index: A,
                                   offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSample cube depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_depth_cube,
                                   s: sampler,
                                   coords: vec3<f32>) -> f32
      </xmp>

  <tr algorithm="textureSample cube depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSample(t: texture_depth_cube_array,
                                   s: sampler,
                                   coords: vec3<f32>,
                                   array_index: A) -> f32
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture|sampled=] or [=type/depth texture|depth=]
  texture to sample.
  <tr><td>`s`<td>
  The [=sampler=] type.
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.
  <tr><td>`array_index`<td>
  The 0-based texture array index to sample.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

The sampled value.

An [=indeterminate value=] results if called in [=uniform control flow|non-uniform control flow=].

### `textureSampleBias` ### {#texturesamplebias}

Samples a texture with a bias to the mip level.

[=shader-creation error|Must=] only be used in a [=fragment=] shader stage.

If [=uniformity analysis=] cannot prove a call to this function is in [=uniform control flow=],
then a [=trigger/derivative_uniformity=] [=diagnostic=] is [=triggered=].

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureSampleBias 2d">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: texture_2d<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       bias: f32) -> vec4<f32>
      </xmp>

<tr algorithm="textureSampleBias 2d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: texture_2d<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       bias: f32,
                                       offset: vec2<i32>) -> vec4<f32>
      </xmp>

<tr algorithm="textureSampleBias 2d array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: texture_2d_array<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       bias: f32) -> vec4<f32>
      </xmp>

<tr algorithm="textureSampleBias 2d array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: texture_2d_array<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       bias: f32,
                                       offset: vec2<i32>) -> vec4<f32>
      </xmp>

<tr algorithm="textureSampleBias 3d">
    <td><var ignore>T</var> is `texture_3d<f32>`, or `texture_cube<f32>`
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: T,
                                       s: sampler,
                                       coords: vec3<f32>,
                                       bias: f32) -> vec4<f32>
      </xmp>

<tr algorithm="textureSampleBias 3d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: texture_3d<f32>,
                                       s: sampler,
                                       coords: vec3<f32>,
                                       bias: f32,
                                       offset: vec3<i32>) -> vec4<f32>
      </xmp>

<tr algorithm="textureSampleBias cube array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBias(t: texture_cube_array<f32>,
                                       s: sampler,
                                       coords: vec3<f32>,
                                       array_index: A,
                                       bias: f32) -> vec4<f32>
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture=] to sample.
  <tr><td>`s`<td>
  The [=type/sampler=] type.
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.
  <tr><td>`array_index`<td>
  The 0-based texture array index to sample.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`bias`<td>
  The bias to apply to the mip level before sampling.<br>
  This value [=behavioral requirement|will=] be clamped in the range `[-16.0, 15.99]`.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

The sampled value.

### `textureSampleCompare` ### {#texturesamplecompare}

Samples a [=type/depth texture=] and compares the sampled depth values against a reference value.

[=shader-creation error|Must=] only be used in a [=fragment=] shader stage.

If [=uniformity analysis=] cannot prove a call to this function is in [=uniform control flow=],
then a [=trigger/derivative_uniformity=] [=diagnostic=] is [=triggered=].

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureSampleCompare 2d depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompare(t: texture_depth_2d,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          depth_ref: f32) -> f32
      </xmp>

  <tr algorithm="textureSampleCompare 2d depth offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompare(t: texture_depth_2d,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          depth_ref: f32,
                                          offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSampleCompare 2d array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          array_index: A,
                                          depth_ref: f32) -> f32
      </xmp>

  <tr algorithm="textureSampleCompare 2d depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                          s: sampler_comparison,
                                          coords: vec2<f32>,
                                          array_index: A,
                                          depth_ref: f32,
                                          offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSampleCompare cube depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompare(t: texture_depth_cube,
                                          s: sampler_comparison,
                                          coords: vec3<f32>,
                                          depth_ref: f32) -> f32
      </xmp>

  <tr algorithm="textureSampleCompare cube depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompare(t: texture_depth_cube_array,
                                          s: sampler_comparison,
                                          coords: vec3<f32>,
                                          array_index: A,
                                          depth_ref: f32) -> f32
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/depth texture=] to sample.
  <tr><td>`s`<td>
  The [=type/sampler_comparison=] type.
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.
  <tr><td>`array_index`<td>
  The 0-based texture array index to sample.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`depth_ref`<td>
  The reference value to compare the sampled depth value against.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

A value in the range `[0.0..1.0]`.

Each sampled texel is compared against the reference value using the comparison
operator defined by the `sampler_comparison`, resulting in either a `0` or `1`
value for each texel.

If the sampler uses bilinear filtering then the returned value is
the filtered average of these values, otherwise the comparison result of a
single texel is returned.

An [=indeterminate value=] results if called in [=uniform control flow|non-uniform control flow=].

### `textureSampleCompareLevel` ### {#texturesamplecomparelevel}

Samples a [=type/depth texture=] and compares the sampled depth values against a reference value.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureSampleCompareLevel 2d depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompareLevel(t: texture_depth_2d,
                                               s: sampler_comparison,
                                               coords: vec2<f32>,
                                               depth_ref: f32) -> f32
      </xmp>

  <tr algorithm="textureSampleCompareLevel 2d depth offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompareLevel(t: texture_depth_2d,
                                               s: sampler_comparison,
                                               coords: vec2<f32>,
                                               depth_ref: f32,
                                               offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSampleCompareLevel 2d depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                               s: sampler_comparison,
                                               coords: vec2<f32>,
                                               array_index: A,
                                               depth_ref: f32) -> f32
      </xmp>

  <tr algorithm="textureSampleCompareLevel 2d depth array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
    <xmp highlight=wgsl>
      @must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                             s: sampler_comparison,
                                             coords: vec2<f32>,
                                             array_index: A,
                                             depth_ref: f32,
                                             offset: vec2<i32>) -> f32
    </xmp>

  <tr algorithm="textureSampleCompareLevel cube depth">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompareLevel(t: texture_depth_cube,
                                               s: sampler_comparison,
                                               coords: vec3<f32>,
                                               depth_ref: f32) -> f32
      </xmp>

  <tr algorithm="textureSampleCompareLevel cube depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleCompareLevel(t: texture_depth_cube_array,
                                               s: sampler_comparison,
                                               coords: vec3<f32>,
                                               array_index: A,
                                               depth_ref: f32) -> f32
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/depth texture=] to sample.
  <tr><td>`s`<td>
  The [=type/sampler_comparison=] type.
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.
  <tr><td>`array_index`<td>
  The 0-based texture array index to sample.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`depth_ref`<td>
  The reference value to compare the sampled depth value against.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

A value in the range `[0.0..1.0]`.

The `textureSampleCompareLevel` function is the same as `textureSampleCompare`, except that:

* `textureSampleCompareLevel` always samples texels from mip level 0.
    * The function does not compute derivatives.
    * There is no requirement for `textureSampleCompareLevel` to be invoked in [=uniform control flow=].
* `textureSampleCompareLevel` may be invoked in any shader stage.

### `textureSampleGrad` ### {#texturesamplegrad}

Samples a texture using explicit gradients.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureSampleGrad 2d">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: texture_2d<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       ddx: vec2<f32>,
                                       ddy: vec2<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleGrad 2d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: texture_2d<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       ddx: vec2<f32>,
                                       ddy: vec2<f32>,
                                       offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleGrad 2d array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: texture_2d_array<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       ddx: vec2<f32>,
                                       ddy: vec2<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleGrad 2d array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: texture_2d_array<f32>,
                                       s: sampler,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       ddx: vec2<f32>,
                                       ddy: vec2<f32>,
                                       offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleGrad 3d">
    <td><var ignore>T</var> is `texture_3d<f32>`, or `texture_cube<f32>`
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: T,
                                       s: sampler,
                                       coords: vec3<f32>,
                                       ddx: vec3<f32>,
                                       ddy: vec3<f32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleGrad 3d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: texture_3d<f32>,
                                       s: sampler,
                                       coords: vec3<f32>,
                                       ddx: vec3<f32>,
                                       ddy: vec3<f32>,
                                       offset: vec3<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleGrad cube array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleGrad(t: texture_cube_array<f32>,
                                       s: sampler,
                                       coords: vec3<f32>,
                                       array_index: A,
                                       ddx: vec3<f32>,
                                       ddy: vec3<f32>) -> vec4<f32>
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture=] to sample.
  <tr><td>`s`<td>
  The [=type/sampler=].
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.
  <tr><td>`array_index`<td>
  The 0-based texture array index to sample.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`ddx`<td>
  The x direction derivative vector used to compute the sampling locations.
  <tr><td>`ddy`<td>
  The y direction derivative vector used to compute the sampling locations.
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

The sampled value.

### `textureSampleLevel` ### {#texturesamplelevel}

Samples a texture using an explicit mip level.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureSampleLevel 2d">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_2d<f32>,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        level: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel 2d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_2d<f32>,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        level: f32,
                                        offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel 2d array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        array_index: A,
                                        level: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel 2d array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        array_index: A,
                                        level: f32,
                                        offset: vec2<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel 3d">
    <td><var ignore>T</var> is `texture_3d<f32>`, or `texture_cube<f32>`
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: T,
                                        s: sampler,
                                        coords: vec3<f32>,
                                        level: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel 3d offset">
    <td>
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_3d<f32>,
                                        s: sampler,
                                        coords: vec3<f32>,
                                        level: f32,
                                        offset: vec3<i32>) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel cube array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_cube_array<f32>,
                                        s: sampler,
                                        coords: vec3<f32>,
                                        array_index: A,
                                        level: f32) -> vec4<f32>
      </xmp>

  <tr algorithm="textureSampleLevel 2d depth">
    <td><var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_depth_2d,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        level: L) -> f32
      </xmp>

  <tr algorithm="textureSampleLevel 2d depth offset">
    <td><var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_depth_2d,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        level: L,
                                        offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSampleLevel 2d depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        array_index: A,
                                        level: L) -> f32
      </xmp>

  <tr algorithm="textureSampleLevel 2d depth array offset">
    <td><var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                        s: sampler,
                                        coords: vec2<f32>,
                                        array_index: A,
                                        level: L,
                                        offset: vec2<i32>) -> f32
      </xmp>

  <tr algorithm="textureSampleLevel cube depth">
    <td><var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_depth_cube,
                                        s: sampler,
                                        coords: vec3<f32>,
                                        level: L) -> f32
      </xmp>

  <tr algorithm="textureSampleLevel cube depth array">
    <td><var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>L</var> is [=i32=], or [=u32=]
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleLevel(t: texture_depth_cube_array,
                                        s: sampler,
                                        coords: vec3<f32>,
                                        array_index: A,
                                        level: L) -> f32
      </xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture|sampled=] or [=type/depth texture|depth=] texture to
  sample.
  <tr><td>`s`<td>
  The [=sampler=] type.
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.
  <tr><td>`array_index`<td>
  The 0-based texture array index to sample.<br>
  This value [=behavioral requirement|will=] be clamped to the range `[0, textureNumLayers(t) - 1]`.
  <tr><td>`level`<td>
  The mip level, with level 0 containing a full size version of the texture.
  For the functions where `level` is a `f32`, fractional values may interpolate
  between two levels if the format is filterable according to the
  [Texture Format Capabilities](https://gpuweb.github.io/gpuweb/#texture-format-caps).
  <tr><td>`offset`<td>
  The optional texel offset applied to the unnormalized texture coordinate
  before sampling the texture. This offset is applied before applying any
  texture wrapping modes.<br>
  The `offset` expression [=shader-creation error|must=] be a [=const-expression=] (e.g. `vec2<i32>(1, 2)`).<br>
  Each `offset` component [=shader-creation error|must=] be at least `-8` and at most `7`. Values outside
  of this range will result in a [=shader-creation error=].
</table>

**Returns:**

The sampled value.

### `textureSampleBaseClampToEdge` ### {#textureSampleBaseClampToEdge}

Samples a texture view at its base level,
with texture coordinates clamped to the edge as described below.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>

  <tr algorithm="textureSampleBaseClampToEdge">
    <td><var ignore>T</var> is `texture_2d<f32>` or `texture_external`
    <td>
      <xmp highlight=wgsl>
        @must_use fn textureSampleBaseClampToEdge(t: T,
                                                  s: sampler,
                                                  coords: vec2<f32>) -> vec4<f32>
      </xmp>
</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/sampled texture|sampled=] or [=type/external texture|external=] texture to sample.
  <tr><td>`s`<td>
  The [=type/sampler=] type.
  <tr><td>`coords`<td>
  The texture coordinates used for sampling.

  Before sampling, the given coordinates [=behavioral requirement|will=] be clamped to the rectangle

  > [ *half_texel*, 1 - *half_texel* ]

  where

  >  *half_texel* = vec2(0.5) / vec2&lt;f32&gt;(textureDimensions(t))

  Note: The half-texel adjustment ensures that,
  independent of the sampler's {{GPUAddressMode|addressing}}
  and {{GPUFilterMode|filter}} modes,
  wrapping will not occur.
  That is, when sampling near an edge, the sampled texels
  will be at or adjacent to that edge, and not selected from the opposite edge.
</table>

**Returns:**

The sampled value.

### `textureStore` ### {#texturestore}

Writes a single texel to a texture.

<table class='data'>
  <thead>
    <tr><td style="width:25%">Parameterization<th>Overload
  </thead>
  <tr algorithm="textureStore 1d">
    <td>|F| is a [=texel format=]<br>
        <var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/write=] or [=access/read_write=]<br>
        <var ignore>CF</var> depends on the storage texel format |F|.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        fn textureStore(t: texture_storage_1d<F,AM>,
                        coords: C,
                        value: vec4<CF>)
      </xmp>

  <tr algorithm="textureStore 2d">
    <td>|F| is a [=texel format=]<br>
        <var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/write=] or [=access/read_write=]<br>
        <var ignore>CF</var> depends on the storage texel format |F|.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        fn textureStore(t: texture_storage_2d<F,AM>,
                        coords: vec2<C>,
                        value: vec4<CF>)
      </xmp>

  <tr algorithm="textureStore 2d array">
    <td>|F| is a [=texel format=]<br>
        <var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/write=] or [=access/read_write=]<br>
        <var ignore>A</var> is [=i32=], or [=u32=]<br>
        <var ignore>CF</var> depends on the storage texel format |F|.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        fn textureStore(t: texture_storage_2d_array<F,AM>,
                        coords: vec2<C>,
                        array_index: A,
                        value: vec4<CF>)
      </xmp>

  <tr algorithm="textureStore 3d">
    <td>|F| is a [=texel format=]<br>
        <var ignore>C</var> is [=i32=], or [=u32=]<br>
        <var ignore>AM</var> is [=access/write=] or [=access/read_write=]<br>
        <var ignore>CF</var> depends on the storage texel format |F|.
        [See the texel format table](#storage-texel-formats) for the mapping of texel
        format to channel format.
    <td>
      <xmp highlight=wgsl>
        fn textureStore(t: texture_storage_3d<F,AM>,
                        coords: vec3<C>,
                        value: vec4<CF>)
      </xmp>

</table>

**Parameters:**

<table class='data'>
  <tr><td>`t`<td>
  The [=type/write-only storage texture=] or
  [=type/read-write storage texture=]
  <tr><td>`coords`<td>
  The 0-based texel coordinate.<br>
  <tr><td>`array_index`<td>
  The 0-based texture array index.
  <tr><td>`value`<td>
  The new texel value.
  `value` is converted using the [=inverse channel transfer function=].
</table>

**Note:**

The [=logical texel address=] is invalid if:
* any element of `coords` is outside the range `[0, textureDimensions(t))`
    for the corresponding element, or
* `array_index` is outside the range of `[0, textureNumLayers(t))`

If the logical texel addresss is invalid, the built-in function [=behavioral requirement|will=] not be executed.

## Atomic Built-in Functions ## {#atomic-builtin-functions}

Atomic built-in functions can be used to read/write/read-modify-write atomic
objects. They are the only operations allowed on [[#atomic-types]].

All atomic built-in functions use a `relaxed` [[#memory-semantics|memory
ordering]].  This means synchronization and ordering guarantees only apply among
atomic operations acting on the same [=memory locations=].  No synchronization
or ordering guarantees apply between atomic and non-atomic memory accesses, or
between atomic accesses acting on different memory locations.

Atomic built-in functions [=shader-creation error|must not=] be used in a [=vertex=] shader stage.

The address space `AS` of the `atomic_ptr` parameter in all atomic built-in
functions [=shader-creation error|must=] be either [=address spaces/storage=] or [=address spaces/workgroup=].

|T| [=shader-creation error|must=] be either [=u32=] or [=i32=]

### Atomic Load ### {#atomic-load}

```wgsl
fn atomicLoad(atomic_ptr: ptr<AS, atomic<T>, read_write>) -> T
```

Returns the atomically loaded the value pointed to by `atomic_ptr`.
It does not [=atomic modification|modify=] the object.

### Atomic Store ### {#atomic-store}

```wgsl
fn atomicStore(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T)
```

Atomically stores the value `v` in the atomic object pointed to by `atomic_ptr`.

### Atomic Read-modify-write ### {#atomic-rmw}

```wgsl
fn atomicAdd(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
fn atomicSub(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
fn atomicMax(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
fn atomicMin(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
fn atomicAnd(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
fn atomicOr(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
fn atomicXor(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
```
Each function performs the following steps atomically:

1. Load the original value pointed to by `atomic_ptr`.
2. Obtains a new value by performing the operation (e.g. max) from the function
    name with the value |v|.
3. Store the new value using `atomic_ptr`.

Each function returns the original value stored in the atomic object.

```wgsl
fn atomicExchange(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T
```

Atomically stores the value `v` in the atomic object pointed to
`atomic_ptr` and returns the original value stored in the atomic object.

```wgsl
fn atomicCompareExchangeWeak(
      atomic_ptr: ptr<AS, atomic<T>, read_write>,
      cmp: T,
      v: T) -> __atomic_compare_exchange_result<T>

struct __atomic_compare_exchange_result<T> {
  old_value : T; // old value stored in the atomic
  exchanged : bool; // true if the exchange was done
}
```

Note: A value cannot be explicitly declared with the type
`__atomic_compare_exchange_result`, but a value may infer the type.

Performs the following steps atomically:

1. Load the original value pointed to by `atomic_ptr`.
2. Compare the original value to the value `cmp` using an equality operation.
3. Store the value `v` `only if` the result of the equality comparison was `true`.

Returns a two member structure, where the first member, `old_value`, is the
original value of the atomic object and the second member, `exchanged`, is
whether or not the comparison succeeded.

Note: The equality comparison may spuriously fail on some implementations. That
is, the second component of the result vector may be `false` even if the first
component of the result vector equals `cmp`.

## Data Packing Built-in Functions ## {#pack-builtin-functions}

Data packing builtin functions can be used to encode values using data formats that
do not correspond directly to types in WGSL.
This enables a program to write many densely packed values to memory, which can
reduce a shader's memory bandwidth demand.

Each builtin applies the *inverse* of a [=channel transfer function=] to several input values, then combines
their results into a single output value.

Note: For packing unorm values, the normalized floating point values are in the interval [0.0, 1.0].

Note: For packing snorm values, the normalized floating point values are in the interval [-1.0, 1.0].

### `pack4x8snorm` ### {#pack4x8snorm-builtin}
<table class='data builtin'>
  <tr algorithm="packing 4x8snorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack4x8snorm(e: vec4<f32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Converts four normalized floating point values to 8-bit signed integers, and then combines them
        into one `u32` value.

        Component `e[i]` of the input is converted to an 8-bit twos complement integer value
        &lfloor; 0.5 + 127 &times; min(1, max(-1, e[i])) &rfloor; which is then placed in bits
        8 &times; `i` through
        8 &times; `i` + 7 of the result.
</table>

### `pack4x8unorm` ### {#pack4x8unorm-builtin}
<table class='data builtin'>
  <tr algorithm="packing 4x8unorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack4x8unorm(e: vec4<f32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Converts four normalized floating point values to 8-bit unsigned integers, and then combines them
        into one `u32` value.

        Component `e[i]` of the input is converted to an 8-bit unsigned integer value
        &lfloor; 0.5 + 255 &times; min(1, max(0, e[i])) &rfloor; which is then placed in bits
        8 &times; `i` through
        8 &times; `i` + 7 of the result.
</table>

### `pack4xI8` ### {#pack4xI8-builtin}
<table class='data builtin'>
  <tr algorithm="packing 4xI8">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack4xI8(e: vec4<i32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Pack the lower 8 bits of each component of `e` into a [=u32=] value and drop all the unused bits.

        Component `e[i]` of the input is mapped to bits
        8 &times; `i` through
        8 &times; `i` + 7 of the result.
</table>

### `pack4xU8` ### {#pack4xU8-builtin}
<table class='data builtin'>
  <tr algorithm="packing 4xU8">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack4xU8(e: vec4<u32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Pack the lower 8 bits of each component of `e` into a [=u32=] value and drop all the unused bits.

        Component `e[i]` of the input is mapped to bits
        8 &times; `i` through
        8 &times; `i` + 7 of the result.
</table>

### `pack4xI8Clamp` ### {#pack4xI8Clamp-builtin}
<table class='data builtin'>
  <tr algorithm="packing 4xI8Clamp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack4xI8Clamp(e: vec4<i32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Clamp each component of `e` in the range [-128, 127] and then pack the lower 8 bits of each
        component into a [=u32=] value.

        Component `e[i]` of the input is mapped to bits
        8 &times; `i` through
        8 &times; `i` + 7 of the result.
</table>

### `pack4xU8Clamp` ### {#pack4xU8Clamp-builtin}
<table class='data builtin'>
  <tr algorithm="packing 4xU8Clamp">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack4xU8Clamp(e: vec4<u32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Clamp each component of `e` in the range of [0, 255] and then pack the lower 8 bits of each
        component into a [=u32=] value.

        Component `e[i]` of the input is mapped to bits
        8 &times; `i` through
        8 &times; `i` + 7 of the result.
</table>

### `pack2x16snorm` ### {#pack2x16snorm-builtin}
<table class='data builtin'>
  <tr algorithm="packing 2x16snorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack2x16snorm(e: vec2<f32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Converts two normalized floating point values to 16-bit signed integers, and then combines them
        into one `u32` value.<br>
        Component `e[i]` of the input is converted to a 16-bit twos complement integer value
        &lfloor; 0.5 + 32767 &times; min(1, max(-1, e[i])) &rfloor; which is then placed in bits
        16 &times; `i` through
        16 &times; `i` + 15 of the result.
</table>

### `pack2x16unorm` ### {#pack2x16unorm-builtin}
<table class='data builtin'>
  <tr algorithm="packing 2x16unorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack2x16unorm(e: vec2<f32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Converts two normalized floating point values to 16-bit unsigned integers, and then combines them
        into one `u32` value.<br>
        Component `e[i]` of the input is converted to a 16-bit unsigned integer value
        &lfloor; 0.5 + 65535 &times; min(1, max(0, e[i])) &rfloor; which is then placed in bits
        16 &times; `i` through
        16 &times; `i` + 15 of the result.
</table>

### `pack2x16float` ### {#pack2x16float-builtin}
<table class='data builtin'>
  <tr algorithm="packing 2x16float">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn pack2x16float(e: vec2<f32>) -> u32
      </xmp>
  <tr>
    <td>Description
    <td>Converts two floating point values to half-precision floating point numbers, and then combines
        them into one `u32` value.<br>
        Component `e[i]` of the input is converted to a [[!IEEE-754|IEEE-754]] binary16 value, which is then
        placed in bits
        16 &times; `i` through
        16 &times; `i` + 15 of the result.
        See [[#floating-point-conversion]].

        If either `e[0]` or `e[1]` is outside the finite range of binary16 then:
        * It is a [=shader-creation error=] if `e` is a [=const-expression=].
        * It is a [=pipeline-creation error=] if `e` is an [=override-expression=].
        * Otherwise the result is an [=indeterminate value=] for u32.
</table>

## Data Unpacking Built-in Functions ## {#unpack-builtin-functions}

Data unpacking builtin functions can be used to decode values in
data formats that do not correspond directly to types in WGSL.
This enables a program to read many densely packed values from memory, which can
reduce a shader's memory bandwidth demand.

Each builtin breaks up an input value into channels, then applies a [=channel transfer function=] to each.

Note: For unpacking unorm values, the normalized floating point result is in the interval [0.0, 1.0].

Note: For unpacking snorm values, the normalized floating point result is in the interval [-1.0, 1.0].

### `unpack4x8snorm` ### {#unpack4x8snorm-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 4x8snorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack4x8snorm(e: u32) -> vec4<f32>
      </xmp>
  <tr>
    <td>Description
    <td>Decomposes a 32-bit value into four 8-bit chunks, then reinterprets
        each chunk as a signed normalized floating point value.<br>
        Component `i` of the result is max(v &div; 127, -1), where `v` is the interpretation of
        bits 8&times;`i` through 8&times;`i + 7` of `e` as a twos-complement signed integer.
</table>

### `unpack4x8unorm` ### {#unpack4x8unorm-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 4x8unorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack4x8unorm(e: u32) -> vec4<f32>
      </xmp>
  <tr>
    <td>Description
    <td>Decomposes a 32-bit value into four 8-bit chunks, then reinterprets
        each chunk as an unsigned normalized floating point value.<br>
        Component `i` of the result is `v` &div; 255, where `v` is the interpretation of
        bits 8&times;`i` through 8&times;`i + 7` of `e` as an unsigned integer.
</table>

### `unpack4xI8` ### {#unpack4xI8-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 4xI8">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack4xI8(e: u32) -> vec4<i32>
      </xmp>
  <tr>
    <td>Description
    <td>`e` is interpreted as a vector with four 8-bit signed integer components. Unpack `e` into a vec4&lt;i32&gt; with sign extension.
</table>

### `unpack4xU8` ### {#unpack4xU8-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 4xU8">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack4xU8(e: u32) -> vec4<u32>
      </xmp>
  <tr>
    <td>Description
    <td>`e` is interpreted as a vector with four 8-bit unsigned integer components. Unpack `e` into a vec4&lt;u32&gt; with zero extension.
</table>


### `unpack2x16snorm` ### {#unpack2x16snorm-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 2x16snorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack2x16snorm(e: u32) -> vec2<f32>
      </xmp>
  <tr>
    <td>Description
    <td>Decomposes a 32-bit value into two 16-bit chunks, then reinterprets
        each chunk as a signed normalized floating point value.<br>
        Component `i` of the result is max(v &div; 32767, -1), where `v` is the interpretation of
        bits 16&times;`i` through 16&times;`i + 15` of `e` as a twos-complement signed integer.
</table>

### `unpack2x16unorm` ### {#unpack2x16unorm-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 2x16unorm">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack2x16unorm(e: u32) -> vec2<f32>
      </xmp>
  <tr>
    <td>Description
    <td>Decomposes a 32-bit value into two 16-bit chunks, then reinterprets
        each chunk as an unsigned normalized floating point value.<br>
        Component `i` of the result is `v` &div; 65535, where `v` is the interpretation of
        bits 16&times;`i` through 16&times;`i + 15` of `e` as an unsigned integer.
</table>

### `unpack2x16float` ### {#unpack2x16float-builtin}
<table class='data builtin'>
  <tr algorithm="unpacking 2x16float">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @const @must_use fn unpack2x16float(e: u32) -> vec2<f32>
      </xmp>
  <tr>
    <td>Description
    <td>Decomposes a 32-bit value into two 16-bit chunks, and reinterpets each chunk
        as a floating point value.<br>
        Component `i` of the result is the f32 representation of `v`,
        where `v` is the interpretation of bits 16&times;`i` through 16&times;`i + 15` of `e`
        as an [[!IEEE-754|IEEE-754]] binary16 value.
        See [[#floating-point-conversion]].
</table>

## Synchronization Built-in Functions ## {#sync-builtin-functions}

All synchronization functions execute a [=control barrier=] with
Acquire/Release [[#memory-semantics|memory ordering]].
That is, all synchronization functions, and affected memory and atomic
operations are ordered in [[#program-order|program order]] relative to the
synchronization function.
Additionally, the affected memory and atomic operations program-ordered before
the synchronization function must be visible to all other threads in the
workgroup before any affected memory or atomic operation program-ordered after
the synchronization function is executed by a member of the workgroup.

All synchronization functions use the `Workgroup` [=memory scope=].<br>
All synchronization functions have a `Workgroup` [=execution scope=].<br>
All synchronization functions [=shader-creation error|must=] only be used in
the [=compute=] shader stage.
All synchronization functions [=shader-creation error|must=] only be invoked in
[=uniform control flow=].

### `storageBarrier` ### {#storageBarrier-builtin}

<table class='data builtin'>
  <tr algorithm="storageBarrier">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        fn storageBarrier()
      </xmp>
  <tr>
    <td>Description
    <td>Executes a [=control barrier=] synchronization function that affects
    memory and atomic operations in the [=address spaces/storage=] address
    space.
</table>

### `textureBarrier` ### {#textureBarrier-builtin}

<table class='data builtin'>
  <tr algorithm="textureBarrier">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        fn textureBarrier()
      </xmp>
  <tr>
    <td>Description
    <td>Executes a [=control barrier=] synchronization function that affects
    memory operations in the [=address spaces/handle=] address space.
</table>

### `workgroupBarrier` ### {#workgroupBarrier-builtin}

<table class='data builtin'>
  <tr algorithm="workgroupBarrier">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        fn workgroupBarrier()
      </xmp>
  <tr>
    <td>Description
    <td>Executes a [=control barrier=] synchronization function that affects
    memory and atomic operations in the [=address spaces/workgroup=] address
    space.
</table>

### `workgroupUniformLoad` ### {#workgroupUniformLoad-builtin}

<table class='data builtin'>
  <tr algorithm="workgroupUniformLoad">
    <td style="width:10%">Overload
    <td class="nowrap">
      <xmp highlight=wgsl>
        @must_use fn workgroupUniformLoad(p : ptr<workgroup, T>) -> T
      </xmp>
  <tr>
    <td>Parameterization
    <td>`T` is a [=type/concrete=] [=plain type=] with a [=fixed footprint=]
    that does not contain any [=atomic types=]
  <tr>
    <td>Description
    <td>Returns the value pointed to by `p` to all invocations in the workgroup.
    The return value is [=uniform value|uniform=].
    `p` [=shader-creation error|must=] be a [=uniform value=].

    Executes a [=control barrier=] synchronization function that affects
    memory and atomic operations in the [=address spaces/workgroup=] address
    space.
</table>

# Grammar for Recursive Descent Parsing # {#grammar-recursive-descent}

This section is non-normative.

The WGSL grammar is specified in a form suitable for an LALR(1) parser.
An implementation may want to use a recursive-descent parser instead.

The normative grammar cannot be used directly in a recursive-descent parser, because
several of its rules are left-recursive.
A grammar rule is directly left-recursive when the nonterminal being defined appears first
in one of its productions.

The following is the WGSL grammar, but mechanically transformed to:
* Eliminate direct and indirect left-recursion.
* Avoid empty productions. (That is, avoid epsilon-rules.)
* Bring together common prefixes among sibling productions.

However, it is not LL(1).
For some nonterminals, several productions have common lookahead sets.
For example, all productions for the `attribute` nonterminal start with the `attr` token.
A more subtle example is `global_decl`, where three productions start with an `attribute *`
phrase, but then are distinguished by tokens `fn`, `override`, and `var`.


For the sake of brevity, many token definitions are not repeated.
Use token definitions from the main part of the specification.


<pre class=include>
path: wgsl.recursive.bs.include
</pre>

# Appendix A: The `text/wgsl` Media Type # {#text-wgsl-media-type}

The Internet Assigned Numbers Authority (IANA) maintains a registry of media types, at [[IANA-MEDIA-TYPES]].

The following is the definition of the `text/wgsl` media type for WGSL modules.
It has been registered at IANA,
appearing at [https://www.iana.org/assignments/media-types/text/wgsl](https://www.iana.org/assignments/media-types/text/wgsl).

: Type name
:: text
: Subtype name
:: wgsl
: Required parameters
:: N/A
: Optional parameters
:: None
: Encoding considerations
::  binary
::  WGSL is Unicode text using the UTF-8 encoding, with no byte order mark (BOM).
    See [[!WGSL]] Section 3. Textual Structure.
: Security considerations:
:: WebGPU Shading Language (WGSL) is a programming language for GPU
    code to be executed in the context of the WebGPU API. For security
    considerations, see [[!WebGPU]] Section 2.1 Security Considerations.
    For privacy considerations, see [[!WebGPU]] Section 2.2 Privacy
    Considerations.
: Interoperability considerations:
:: Implementations of WebGPU may have different capabilities, and
    these differences may affect what features may be exercised by
    WGSL programs. See [[!WebGPU]] Section 3.6 Optional capabilities,
    and [[!WGSL]] Section 11. Language Extensions.

    It is expected that implementations will behave as if this
    registration applies to later editions of WGSL, and its published
    specification references may be updated accordingly from time to
    time.  Although this expectation is unusual among media type
    registrations, it matches widespread industry conventions.
: Published specification:
:: [[!WGSL]]
: Applications that use this media type:
::  Implementations of WebGPU. This is expected to include web browsers.
: Fragment identifier considerations
:: None
: Additional information:
:: Magic number(s): None
:: File extension(s): `.wgsl`
:: Macintosh file type code(s): `TEXT`
: Person & email address to contact for further information:
:: David Neto, dneto@google.com, or the Editors listed in WGSL.
: Intended usage
:: COMMON
: Author
:: W3C. See the Editors listed in WGSL.
: Change controller
:: W3C
: Normative References
:: [[!WebGPU]] W3C, "WebGPU” W3C Working Draft, January 2023.  https://w3.org/TR/webgpu
:: [[!WGSL]] W3C, “WebGPU Shading Language” W3C Working Draft, January 2023.  https://w3.org/TR/WGSL
